Prevent re-render using React.memo and React.useCallback - javascript

For learning purpose,
I am trying prevent re-render on <InputWithLable /> component whenever i Dismiss a search result (see deploy in Full code)
I have use React.memo but it still re-render. So I think maybe its props is the culprit. I use React.useCallback to handleSearch prop, but it doesn't work.
Full code
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
import React from 'react';
const API_ENDPOINT = 'https://hn.algolia.com/api/v1/search?query=';
const useSemiPersistentState = (key, initialState) => {
const [value, setValue] = React.useState(
localStorage.getItem(key) || initialState
);
React.useEffect(() => {
localStorage.setItem(key, value);
}, [value, key]);
return [value, setValue];
};
function storiesReducer(prevState, action) {
switch (action.type) {
case "SET":
return { ...prevState, data: action.data, isLoading: false, isError: false };
case "REMOVE":
return {
...prevState,
data: prevState.data.filter(
story => action.data.objectID !== story.objectID
)
}
case "ERROR":
return { ...prevState, isLoading: false, isError: true };
default:
throw new Error();
}
}
const App = () => {
const [searchTerm, setSearchTerm] = useSemiPersistentState(
'search',
'Google'
);
const [stories, dispatchStories] = React.useReducer(storiesReducer, { data: [], isLoading: true, isError: false });
const [url, setUrl] = React.useState("");
const handleFetchStories = React.useCallback(() => {
fetch(url)
.then((response) => response.json())
.then((result) => {
console.log(result);
dispatchStories({ type: "SET", data: result.hits })
})
.catch(err => dispatchStories({ type: "ERROR", data: err }))
}, [url])
React.useEffect(() => {
handleFetchStories();
}, [handleFetchStories])
const handleRemoveStory = React.useCallback(
(item) => {
dispatchStories({ type: "REMOVE", data: item });
},
[], // chi render 1 lan vi props khong thay doi
)
const handleSearch = React.useCallback(
(e) => {
setSearchTerm(e.target.value);
},
[],
)
// Chuc nang filter la cua server (vd: database)
// const searchedStories = stories.data ? stories.data.filter(story =>
// story.title.toLowerCase().includes(searchTerm.toLowerCase())
// ) : null; // nghich cai nay!
console.log('App render');
return (
<div>
<h1>My Hacker Stories</h1>
<InputWithLabel
id="search"
value={searchTerm}
isFocused
onInputChange={handleSearch}
>
<strong>Search:</strong>
</InputWithLabel>
<button onClick={() => setUrl(API_ENDPOINT + searchTerm)}>Search!</button>
<hr />
{stories.isError && <h4>ERROR!</h4>}
{stories.isLoading ? <i>Loading...</i>
: <List list={stories.data} onRemoveItem={handleRemoveStory} />}
</div>
);
};
const InputWithLabel = React.memo(
({
id,
value,
type = 'text',
onInputChange,
isFocused,
children,
}) => {
const inputRef = React.useRef();
React.useEffect(() => {
if (isFocused) {
inputRef.current.focus();
}
}, [isFocused]);
console.log('Search render')
return (
<>
<label htmlFor={id}>{children}</label>
<input
ref={inputRef}
id={id}
type={type}
value={value}
onChange={onInputChange}
/>
</>
);
}
);
// Prevent default React render mechanism: Parent rerender -> Child rerender
const List = React.memo(
({ list, onRemoveItem }) =>
console.log('List render') || list.map(item => (
<Item
key={item.objectID}
item={item}
onRemoveItem={onRemoveItem}
/>
))
);
const Item = ({ item, onRemoveItem }) => (
<div>
<span>
<a href={item.url}>{item.title}</a>
</span>
<span>{item.author}</span>
<span>{item.num_comments}</span>
<span>{item.points}</span>
<span>
<button type="button" onClick={() => onRemoveItem(item)}>
Dismiss
</button>
</span>
</div>
);
export default App;

You should not be looking at how many times a component's render function gets called; React is free to call it as many times as it likes (and indeed, in strict mode, it calls them twice to help you not make mistakes).
But to answer your question (with the actual code that uses children):
<InputWithLabel>
<strong>Search:</strong>
</InputWithLabel>
compiles down to
React.createElement(InputWithLabel, null,
React.createElement("strong", null, "Search:"))
the identity of the children prop (the <strong /> element) changes for each render of the parent component since React.createElement() returns new objects for each invocation. Since that identity changes, React.memo does nothing.
If you wanted to (but please don't), you could do
const child = React.useMemo(() => <strong>Search:</strong>);
// ...
<InputWithLabel>{child}</InputWithLabel>
but doing that for all of your markup leads to nigh-unreadable code.

Related

how to implement addItem using react-redux

I've implemented user list and can delete users dispatching action deleteUser().
Now I add user but once I click add button the data is not mapped in the list.
this is a reducer:
case ADD_USERS:
const newId = state.users[state.users.length-1] + 1
return {
...state,
users: [
...state.users,
{
id: newId,
name: action.payload
}
],
loading: false
}
initial state consists of 2 objects and loading key.
The action function is simple:
export function addUser (name) {
return {
type: ADD_USERS,
payload: name
}
and the component is there:
const mapStateToProps = (state) => ({ users: state.users });
const mapDispatchToProps = (dispatch) => {
return {
deleteUser: id => {
dispatch(deleteUser(id))
},
addUser: name => {
dispatch(addUsers(name))
}
}
};
const Users = (props) => {
const { users } = props.users;
useEffect(() => {
getUsers();
}, []);
return (
<>
<input type='text' placeholder='name..'/>
<button onClick={() => props.addUser(name)}>add</button>
<h2>Users</h2>
{users.map((user) => {
return (
<div className="d-flex justify-content-between align-items-center mb-1">
<li>{user.name}</li>
<button onClick={() => props.deleteUser(user.id)}>x</button>
</div>
);
})}
</>
);
};
}
I consider getUsers don't work or I can be wrong. cause I map state to props and display the data inside {user.name}
I think it should work same with getUsers()
Maybe this is not the only one issue, but at least this looks strange to me:
const { users } = props.users;
Because, with the line above you are creating a constant with value from props.users.users. You have not shown how you use the Users component and what it gets from outside, but this looks at least strange to me.
<button onClick={() => props.addUser(name)}>add</button>
Your button calls addUser with a variable name, but that variable doesn't exist!
You need to change your input into a controlled component so that you can call addUser with the name from the input field.
const [name, setName] = useState("");
return (
<>
<input
type="text"
placeholder="name.."
value={name}
onChange={(e) => setName(e.target.value)}
/>
<button onClick={() => props.addUser(name)}>add</button>
...

How to get the number of checked checkboxes in React.js?

I started learning React not so long ago. Decided to make some kind of "life checklist" as one of my beginner projects. I have been using Functional Components in the core.
FYI:
I have data.js as an array of objects where "action", "emoji" and unique ID are stored.
I import it into my App.js.
const App = () => {
//Looping over data
const items = data.map((item) => {
return (
<ChecklistItem action={item.action} emoji={item.emoji} key={item.id} />
);
});
return (
<>
<GlobalStyle />
<StyledHeading>Life Checklist</StyledHeading>
<StyledApp>{items}</StyledApp>
<h2>Overall number: {data.length}</h2>
</>
);
};
export default App;
Here is my <ChecklistItem/> component:
const ChecklistItem = ({ action, emoji }) => {
//State
const [isActive, setIsActive] = useState(false);
//Event Handlers
const changeHandler = () => {
setIsActive(!isActive);
};
return (
<StyledChecklistItem isActive={isActive}>
<input type="checkbox" checked={isActive} onChange={changeHandler} />
<StyledEmoji role="img">{emoji}</StyledEmoji>
<StyledCaption>{action}</StyledCaption>
</StyledChecklistItem>
);
};
export default ChecklistItem;
I would be satisfied with the functionality so far, but I need to show how many "active" checklist items were chosen in the parent <App/> component like "You have chosen X items out of {data.length}. How can I achieve this?
I assume that I need to lift the state up, but cannot understand how to implement this properly yet.
You can do that by simply creating a state for storing this particular count of active items.
To do that, you would need to update your <App/> component to something like this
const App = () => {
const [activeItemsCount, setActiveItemsCount] = useState(0);
//Looping over data
const items = data.map((item, index) => {
return (
<ChecklistItem
key={index}
action={item.action}
emoji={item.emoji}
setActiveItemsCount={setActiveItemsCount}
/>
);
});
return (
<>
<h1>Life Checklist</h1>
<div>{items}</div>
<div>Active {activeItemsCount} </div>
<h2>Overall number: {data.length}</h2>
</>
);
};
export default App;
And then in your <ChecklistItem /> component, you would need to accept that setActiveItemsCount function so that you can change the state of the activeItemsCount.
import React, { useState, useEffect } from "react";
const ChecklistItem = ({ action, emoji, setActiveItemsCount }) => {
const [isActive, setIsActive] = useState(false);
const changeHandler = () => {
setIsActive(!isActive);
};
useEffect(() => {
if (!isActive) {
setActiveItemsCount((prevCount) => {
if (prevCount !== 0) {
return prevCount - 1;
}
return prevCount;
});
}
if (isActive) {
setActiveItemsCount((prevCount) => prevCount + 1);
}
}, [isActive, setActiveItemsCount]);
return <input type="checkbox" checked={isActive} onChange={changeHandler} />;
};
export default ChecklistItem;
By using the useEffect and the checks for isActive and 0 value, you can nicely increment or decrement the active count number by pressing the checkboxes.
How about this?
const data = [
{ action: '1', emoji: '1', id: 1 },
{ action: '2', emoji: '2', id: 2 },
{ action: '3', emoji: '3', id: 3 },
];
const ChecklistItem = ({ action, emoji, isActive, changeHandler }) => {
return (
<div isActive={isActive}>
<input type="checkbox" checked={isActive} onChange={changeHandler} />
<div>{emoji}</div>
<div>{action}</div>
</div>
);
};
const PageContainer = () => {
const [checkedItemIds, setCheckedItemIds] = useState([]);
function changeHandler(itemId) {
if (checkedItemIds.indexOf(itemId) > -1) {
setCheckedItemIds((prev) => prev.filter((i) => i !== itemId));
} else {
setCheckedItemIds((prev) => [...prev, itemId]);
}
}
const items = data.map((item) => {
const isActive = checkedItemIds.indexOf(item.id) > -1;
return (
<ChecklistItem
isActive={isActive}
changeHandler={() => changeHandler(item.id)}
action={item.action}
emoji={item.emoji}
key={item.id}
/>
);
});
return (
<div className="bg-gray-100">
<div>{items}</div>
<h2>
You have chosen {checkedItemIds.length} items out of {data.length}
</h2>
</div>
);
};
When data is used by a child component, but the parent needs to be aware of it for various reasons, that should be state in the parent component. That state is then handed to the child as props.
One way to do this would be to initialize your parent component with a piece of state that was an array of boolean values all initialized to false. Map that state into the checkbox components themselves and hand isActive as a prop based on that boolean value. You should then also hand the children a function of the parent that will change the state of the boolean value at a certain index of that array.
Here's a bit of a contrived example:
// Parent.tsx
const [checkBoxes, setCheckboxes] = useState(data.map(data => ({
id: data.id,
action: data.action,
emoji: data.emoji
isActive: false,
})));
const handleCheckedChange = (i) => {
setCheckboxes(checkBoxes => {
checkBoxes[i].isActive = !checkBoxes[i].isActive;
return checkBoxes;
})
}
return(
checkBoxes.map((item, i) =>
<ChecklistItem
action={item.action}
emoji={item.emoji}
key={item.id}
index={i}
isActive={item.isActive}
handleChange={handleCheckedChange}
/>
)
);
// CheckListItem.tsx
const CheckListItem = ({ action, emoji, index, isActive, handleChange }) => (
<StyledChecklistItem isActive={isActive}>
<input type="checkbox" checked={isActive} onChange={() => handleChange(index)} />
<StyledEmoji role="img">{emoji}</StyledEmoji>
<StyledCaption>{action}</StyledCaption>
</StyledChecklistItem>
)

Couldn't correctly initialize state in parent component from children states

I have two React components, namely, Form and SimpleCheckbox.
SimpleCheckbox uses some of the Material UI components but I believe they are irrelevant to my question.
In the Form, useEffect calls api.getCategoryNames() which resolves to an array of categories, e.g, ['Information', 'Investigation', 'Transaction', 'Pain'].
My goal is to access checkboxes' states(checked or not) in the parent component(Form). I have taken the approach suggested in this question.(See the verified answer)
Interestingly, when I log the checks it gives(after api call resolves):
{Pain: false}
What I expect is:
{
Information: false,
Investigation: false,
Transaction: false,
Pain: false,
}
Further More, checks state updates correctly when I click into checkboxes. For example, let's say I have checked Information and Investigation boxes, check becomes the following:
{
Pain: false,
Information: true,
Investigation: true,
}
Here is the components:
const Form = () => {
const [checks, setChecks] = useState({});
const [categories, setCategories] = useState([]);
const handleCheckChange = (isChecked, category) => {
setChecks({ ...checks, [category]: isChecked });
}
useEffect(() => {
api
.getCategoryNames()
.then((_categories) => {
setCategories(_categories);
})
.catch((error) => {
console.log(error);
});
}, []);
return (
{categories.map(category => {
<SimpleCheckbox
label={category}
onCheck={handleCheckChange}
key={category}
id={category}
/>
}
)
}
const SimpleCheckbox = ({ onCheck, label, id }) => {
const [check, setCheck] = useState(false);
const handleChange = (event) => {
setCheck(event.target.checked);
};
useEffect(() => {
onCheck(check, id);
}, [check]);
return (
<FormControl>
<FormControlLabel
control={
<Checkbox checked={check} onChange={handleChange} color="primary" />
}
label={label}
/>
</FormControl>
);
}
What I was missing was using functional updates in setChecks. Hooks API Reference says that: If the new state is computed using the previous state, you can pass a function to setState.
So after changing:
const handleCheckChange = (isChecked, category) => {
setChecks({ ...checks, [category]: isChecked });
}
to
const handleCheckChange = (isChecked, category) => {
setChecks(prevChecks => { ...prevChecks, [category]: isChecked });
}
It has started to work as I expected.
It looks like you're controlling state twice, at the form level and at the checkbox component level.
I eliminated one of those states and change handlers. In addition, I set checks to have an initialState so that you don't get an uncontrolled to controlled input warning
import React, { useState, useEffect } from "react";
import { FormControl, FormControlLabel, Checkbox } from "#material-ui/core";
import "./styles.css";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Form />
</div>
);
}
const Form = () => {
const [checks, setChecks] = useState({
Information: false,
Investigation: false,
Transaction: false,
Pain: false
});
const [categories, setCategories] = useState([]);
console.log("checks", checks);
console.log("categories", categories);
const handleCheckChange = (isChecked, category) => {
setChecks({ ...checks, [category]: isChecked });
};
useEffect(() => {
// api
// .getCategoryNames()
// .then(_categories => {
// setCategories(_categories);
// })
// .catch(error => {
// console.log(error);
// });
setCategories(["Information", "Investigation", "Transaction", "Pain"]);
}, []);
return (
<>
{categories.map(category => (
<SimpleCheckbox
label={category}
onCheck={handleCheckChange}
key={category}
id={category}
check={checks[category]}
/>
))}
</>
);
};
const SimpleCheckbox = ({ onCheck, label, check }) => {
return (
<FormControl>
<FormControlLabel
control={
<Checkbox
checked={check}
onChange={() => onCheck(!check, label)}
color="primary"
/>
}
label={label}
/>
</FormControl>
);
};
If you expect checks to by dynamically served by an api you can write a fetchHandler that awaits the results of the api and updates both slices of state
const fetchChecks = async () => {
let categoriesFromAPI = ["Information", "Investigation", "Transaction", "Pain"] // api result needs await
setCategories(categoriesFromAPI);
let initialChecks = categoriesFromAPI.reduce((acc, cur) => {
acc[cur] = false
return acc
}, {})
setChecks(initialChecks)
}
useEffect(() => {
fetchChecks()
}, []);
I hardcoded the categoriesFromApi variable, make sure you add await in front of your api call statement.
let categoriesFromApi = await axios.get(url)
Lastly, set your initial slice of state to an empty object
const [checks, setChecks] = useState({});

Child component causing too many renderings on parent component when changing global state in React

I am working on a React web application, I have a global state for storing some data, for some reason I happen to see quite unnecessarily renderings on my app!
I have component that looks like this:
const LanguageSkills = () => {
const [languageSelected, setLanguage] = React.useState({})
const { dispatch } = useContext(GlobalStore)
const handleChange = (name: string) => (event: any) => {
setLanguage({ ...languageSelected, [name]: event.target.checked })
}
useEffect(() => {
dispatch({
type: ApplicantActions.FILTER_APPLICANTS,
payload: {
languageSkills: languageSelected,
},
})
}, [dispatch, languageSelected])
return (
<>
{
{languageSkills.map((lang, index) => (
<TermWrapper key={index}>
<GreenCheckbox onChange={handleChange(lang.term)} value="checked" />
<Term>{lang.term}</Term>
</TermWrapper>
))}
}
</>
)
}
This component causes the parent component to render without any action doing from this component, well because the dispatch function is called immediately inside useEffect() once the component gets mounted (at least what I know), how else can I handle this so dispatch only gets called when I click the radio button? Is there any callback or someway that I can call dispatch once the local state changed using setState()?
Any idea how can I use dispatch in such situations?
Update this line
<GreenCheckbox onChange={handleChange(lang.term)} value="checked" />
to this
<GreenCheckbox onChange={() => handleChange(lang.term)} value="checked" />
you are calling the function in render time. give it a callback
UPDATED:
const handleChange = (name: string) => (event: any) => {
setLanguage({ ...languageSelected, [name]: event.target.checked })
}
useEffect(() => {
callMe();
}, [languageSelected])
const callMe = () => {
dispatch({
type: ApplicantActions.FILTER_APPLICANTS,
payload: {
languageSkills: languageSelected,
},
})
}
After several trying I came up with this and it seems fine for me, does not cause anymore parent component to re-render!
const LanguageSkills = () => {
const [isVisible, setIsVisible] = useState(false)
const [state, setState] = React.useState({})
const { dispatch } = useContext(GlobalStore)
const handleChange = (name: string) => (event: React.ChangeEvent<HTMLInputElement>) => {
const obj = { ...state, [name]: event.target.checked }
dispatchLanguageFilter(obj)
setState({ ...state, [name]: event.target.checked })
}
const dispatchLanguageFilter = useCallback(
obj => {
const languageSkills: string[] = []
for (const [key, value] of Object.entries(obj)) {
if (value) {
languageSkills.push(key)
}
}
dispatch({
type: ApplicantActions.FILTER_APPLICANTS,
payload: {
languageSkills: languageSkills,
},
})
},
[dispatch],
)
return (
<>
<Wrapper onClick={() => setIsVisible(!isVisible)}>
<FilterContainerTitle>Kielitaito</FilterContainerTitle>
<Arrow>{!isVisible ? <ArrowDown /> : <ArrowUp />}</Arrow>
</Wrapper>
{isVisible && (
<>
{languageSkills.map((lang, index) => (
<TermWrapper key={index}>
<GreenCheckbox onChange={handleChange(lang.term)} value="checked" />
<Term>{lang.term}</Term>
<TotalAmountWrapper>
<TotalAmount>{lang.totalAmount}</TotalAmount>
</TotalAmountWrapper>
</TermWrapper>
))}
</>
)}
</>
)
}
Not sure if its right way but mission accomplished!

How to implement buttons that receive different data from the API depending on which button is pressed on Redux?

I currently have a code that displays Api data on the page. This is a list :
API has this structure:
{"hij":{
"low":[{......},{.....}],
"all":[{....},{......}]}
}
How to implement such buttons on Redux? Can you help me a little bit? I watched a few dozen videos on YouTube, read many articles and no examples of how to make buttons which to take different data from API....
On React I implement it this way(App.js):
class App extends React.Component {
state = {
day: 1,
data: [],
filteredData: [],
search: "",
shift: "low"
};
componentDidMount() {
this.fetchData();
}
fetchData = async () => {
const response = await fetch(`...`);
const data = (await response.json()).body;
this.setState({data, shift: Object.keys(data)[0]}, this.filter);
};
loadDay = day => {
this.setState({ day }, this.fetchData);
};
updateSearch = e => {
this.setState({search: e.target.value});
};
filter = () => {
this.setState(({ search, data, shift }) => {
const s = search.toLowerCase();
return {
filteredData: data[shift].filter(n =>
n.term.toLowerCase().includes(s)
)
};
});
};
onClick = ({target: { dataset: { shift }}}) => {
this.setState(() => ({ shift }), this.filter);
};
render() {
const { search, shift, data, filteredData } = this.state;
return (
<div>
<TableSearch value={search}
onChange={this.updateSearch}
onSearch={this.filter}/>
{days.map((day, i) => (
<button key={day}
onClick={() => this.loadDay(i)}
className={i === this.state.day ? "active" : ""}>{day}</button>
))}
<br />
{Object.keys(data).map(n => (
<button data-shift={n}
onClick={this.onClick}
className={n === shift ? "active" : ""}>{n} shift</button>
))}
<TableData data={filteredData} />
</div>
);
}
}
There are a number of things to change to make this a redux compatible application, the least of your concerns would be buttons. So instead of answering the button part directly, here's an annotated refactor of your application to Redux:
import { createStore, applyMiddleware } from 'redux';
import { connect, Provider } from 'react-redux';
import thunk from 'redux-thunk';
// Take out common functionality into seperate functions, such as
// running a search here.
function searchFilter (search, data) {
return data.filter(n => n.term.toLowerCase().includes(search));
}
// This is your reducer function which updates the global redux state,
// depending on which action you dispatch:
// see https://redux.js.org/basics/reducers
function reducer (state = {}, action) {
state = { ...state }
switch (action.type) {
case 'SET_SEARCH':
state.search = action.search.toLowerCase();
break;
case 'RUN_FILTER':
state.shift = action.shift || state.shift;
state.search = action.search || state.search;
state.filteredData = searchFilter(state.search, state.data[state.shift]);
break;
case 'LOAD_DATA_START':
state.day = action.day;
break;
case 'LOAD_DATA_END':
state.data = action.data;
state.shift = Object.keys(data)[0];
state.filteredData = searchFilter(state.search, state.data[state.shift]);
break;
}
return state;
}
// This is your store object which contains an initial state, and a reducer
// that will be used for dispatched actions.
// see https://redux.js.org/basics/store
//
// Redux-thunk is used as middleware to support async data fetching which you will
// also need to read up on, although you don't really need to know how it
// works at first.
// see https://github.com/reduxjs/redux-thunk
const store = createStore(
reducer,
{
day: 1,
data: [],
filteredData: [],
search: "",
shift: "departure"
},
applyMiddleware(thunk)
);
// This is a "thunk" called fetch data, again you can read more
// about thunks in the redux-thunk docs
// see https://github.com/reduxjs/redux-thunk
function fetchData (day) {
return async (dispatch) => {
dispatch({ type: 'LOAD_DATA_START', day });
const response = await fetch(`https://api.iev.aero/api/flights/${days[this.state.day]}`);
const data = (await response.json()).body;
dispatch({ type: 'LOAD_DATA_END', data });
}
}
const days = ["23-08-2019", "24-08-2019", "25-08-2019"];
// Stripped down component, it does not handle any of its own state
// all state is passed to it through the redux connect HOC.
class Root extends React.Component {
componentDidMount() {
this.props.onFetchData(this.props.day);
}
render() {
const { search, shift, data, filteredData, onFilter, onSetSearch, onFetchData } = this.props;
return (
<div>
<TableSearch value={search}
onChange={(e) => onSetSearch(e.target.value)}
onSearch={() => onFilter()} />
{days.map((day, i) => (
<button key={day}
onClick={() => onFetchData(day)}
className={i === day ? "active" : ""}>{day}</button>
))}
<br />
{Object.keys(data).map(n => (
<button data-shift={n}
onClick={(e) => onFilter({ shift: e.target.dataset.shift })}
className={n === shift ? "active" : ""}>{n} shift</button>
))}
<TableData data={filteredData} />
</div>
);
}
}
// This is the "connected" version of the component, which is
// your component wrapped in a connect HOC. When the reducer function
// is run, the two functions below will be executed and your component
// inside will re render.
//
// You can read more about this one in react-redux
// https://react-redux.js.org/
const ConnectedRoot = connect(
(state) => state,
(dispatch) => ({
onFilter: (args) => dispatch({ type: 'RUN_FILTER', ...args }),
onSetSearch: (search) => dispatch({ type: 'SET_SEARCH', search }),
onFetchData: (day) => dispatch(fetchData(day))
})
);
// This is your top level component that you would call in ReactDOM.render
// The Provider component is part of react-redux, and you can read about it
// there, but in most cases it is sufficient to drop it at the very top level
// of your application.
// https://react-redux.js.org/
const App = () => (
<Provider store={store}>
<ConnectedRoot />
</Provider>
);

Categories