I am new to react and redux so am confused where to initialize store with dummy data? am using provider in the root component .
the only two ways to access store i found are either using this:-
Provider.childContextTypes = {
store: React.PropTypes.object
}
or by using connect ,
const mapStateToProps = state => ({
state:state.contacts
});
const mapDispatchToProps = dispatch => ({
setDummyData: () => dispatch(setDummyData())
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ComponentName)
but contacts isn't initialized ..
How to approach?
any any links where i can find examples with connect and dummy data will be very helpful
do it either in createStore for whole store or in reducer(s) for each slice.
https://redux.js.org/api/createstore
You can initialize a store in your index.js file (for instance if you used create-react-app). Once you initialize your store, you can pass it to your provider and wrap your app with the provider:
const = createStore(someReducers, someMiddleWareIfYouHaveIt)
<Provider store={store}>
<App />
</Provider>
There are some starter kits here on the ReactJS website as well.
Related
I have a following question.
I was asked to make example project that compares Redux Toolkit Query and Redux Toolkit with use of Fetch API (or Axios).
I have the Redux Toolkit Query part.
How can I add another store?
Should I do:
<ChosenStoreContext>
<Provider store={store}>
<ApiProvider api={api}>
...Rest of the app
</ApiProvider>
</Provider>
</ChosenStoreContext>
with ChosenStoreContext (useContext boolean value) added just to tell components whether they should dispatch query actions or store actions
Or should I go completely other route?
ApiProvider documentation says that it can cause conflicts.
Any tips would be helpful!
An ApiProvider will also just create a store and use a Provider to pass that down - overwriting the original Provider.
Generally, you should have only one store in your application - and you can have both of those examples on different slices in one store, without them influencing each other.
There is an option of having mutiple different providers and sets of hooks using multiple contexts but that is extra work and will not gain you anything.
Just put everything in the same store.
All you need to do is only add a provider in your App and then in your main store file just add reducer from api Reducer and finally add it's middleware look like this:
// fooSlice.js
const fooReducer = createSlice({
//todo
});
export default fooReducer.reducer
//-->> fooApiSlice.js
const fooApiReducer = createApi({
reducerPath: "tag",
baseQuery: fetchBaseQuery({baseUrl: "path"}),
tagTypes: [tag],
endpoints: (build) => ({
getItems: build.query({
//todo
}),
})
})
export default fooApiReducer
//-->> store.js
import fooReducer from "./fooSlice"
import fooApiReducer from "./fooApiSlice"
export const store = configureStore({
reducer: {
foo: fooReducer,
fooApi: fooApiReducer.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({}).concat([
fooApiReducer.middleware
]),
})
//-->> index.js
<Provider store={store}>
<App/>
</Provider>
I have an app using React hooks, and I am also using there Storybook.
After adding Redux I have a small problem.
While adding Provider as global decorator helped me load the initial state for my components and display them in Storybook, now that everythign is in store, I cannot figure out how to add knobs to be able to display my components with different state.
Here's the config file with Provider
const store = createStore(reducer);
addDecorator(Story => (<div
style={style}>
<Provider store={store}>
<Story />
</Provider> </div> ));
And here's one of the stories which worked fine before Redux (with useSelector and useDispatch hooks) was added
const stories = storiesOf('UI Components', module)
stories.addDecorator(withKnobs)
stories.add('Input Button', () => {
const groupId = 'Props'
const statusesKnob = select('Button states', appStates, Object.values(appStates)[0], groupId)
return <InputButton getAppState={statusesKnob} />
})
States
const appStates = [
LOADING: 'LOADING',
INACTIVE: 'INACTIVE',
ERROR:'ERROR',
]
Thanks
I had the same problem.
I finally added the store to the a global variable and used store.dispatch
if decorator.js:
window.REDUX_STORE = store;
in the story:
window.REDUX_STORE.dispatch(...);
I am using React-Redux, but I am not able to figure out how to access a variable in the Redux store inside of my nested components.
How can I share a variable between components, using React-Redux?
For example:
I have an 'index.js' file and 30 nested components. Managing these components becomes difficult after a while.
I have a 'C1.js' component. Let's just say I wrote this code in it.
function Reducer(state = 'example' , action) {
return state;
}
const store = createStore(Reducer)
index.js file:
<Provider store = {store}>
<App/>, document.getElementById('root')
</Provider>
How do I pass the 'store' variable to the 'C1.js' component to the index.js file?
Thanks...
You need to use something called "Connect" to connect your various components to the provider.
In the file that contains your C1.js component:
import {connect} from 'react-redux'
const MyComponent = () => {
let someData = props.someData
return(
//all of your JSX for your component here
)
}
const mapState = state => {
return {
someData: state.someData
}
}
export default connect(mapState)(MyComponent)
In the code above, notice the mapStateFunction. Connect is hooking that up with the Provider, and the state that is on the Provider. So that is where you are able to link whatever properties are on your Provider (React-Redux) state with this particular data.
Now, in your component, you will now have prop.someData
-
In the index file, you have your Provider in the wrong place, you need to change your code to this:
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('app')
)
See, the difference there? The is the React Element (and all of its children that you are asking React to render to the DOM). It is the first parameter of the ReactDOM.render function.
The second parameter to the ReactDom.render function is the element in the DOM where you want it to put all of your React elements.
You did not configure well redux and react. You need to go over the doc of redux to setup correctly. Should get working after that.
I have a code in redux which i exported as
export default connect(mapStateToLinkProps, mapDispatchToLinkProps)(Link);
And in jest test case i have written to test this exported component
//imported the above component as Link
describe('Dashboard component testing', () => {
test('1. Must be an Instance of CreateAssest', () => {
const wrapper = shallow(<FilterLink />);
const inst = wrapper.instance();
expect(inst).toBeInstanceOf(Link);
});
});
For this i'm getting error
Invariant Violation: Could not find "store" in either the context or
props of "Connect(Link)". Either wrap the root component in a
, or explicitly pass "store" as a prop to "Connect(Link)".
When not using redux and exporting only as react component the test cases were working.Now in redux some store issue is coming.please can anyone guide a little in this issue what's happening
You need to wrap your component in Provider in order to be able to use store, like so:
import { Provider, connect } from "react-redux";
let store = createStore(reducer, defaultStoreItems);
<Provider store={store}>
<App />
</Provider>
In the react-redux documentation it states that when using React-redux and connect() importing the store is not recommended. It's an anti-pattern.
http://redux.js.org/docs/faq/StoreSetup.html
Similarly, while you can reference your store instance by importing it
directly, this is not a recommended pattern in Redux. If you create a
store instance and export it from a module, it will become a
singleton. This means it will be harder to isolate a Redux app as a
component of a larger app, if this is ever necessary, or to enable
server rendering, because on the server you want to create separate
store instances for every request.
With React Redux, the wrapper classes generated by the connect()
function do actually look for props.store if it exists, but it's best
if you wrap your root component in and let
React Redux worry about passing the store down. This way components
don't need to worry about importing a store module, and isolating a
Redux app or enabling server rendering is much easier to do later.
How, then, do I access the store from any component of my choosing(even deep down in the application) once I've properly wired in the store to my app? My code properly connects App but I can't get access to the store from any child components at all. store.dispatch() is null, store.getState() is null, etc. I feel that the documentation is lacking in this regard. It's said to be magic but I'd like to know how to use the magic. Do I need to write mapDispatchToProps() again and again for every single container component? A use case would be the currentUser prop that would be available to every single child component in the application. I'd like to pass that down from App to every single child.
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);//App is now a connected component, that part is working
Inside App I have a Login component, and I'd like to dispatch an action inside it. But I need a reference to store, but apparently I'm not supposed to import it.
This is where the concept of containers come into play.
Suppose you wanted to render a Login component inside of your App. You will make a connected container.
Step 1 is to create a simple action:
const LOGIN_ATTEMPT = 'auth/LOGIN_ATTEMPT';
export const login = name => ({
type: LOGIN_ATTEMPT,
payload: { name },
});
You will now use react-redux in order to connect this action to your "presentational component". This will come through to the component as a prop.
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { login } from 'actions/auth'; // your action
import Login from 'components/auth/Login'; // your component to connect it to.
// state refers to the "current state" of your store.
const mapStateToProps = state => ({ currentUser: state.auth.user });
// dispatch refers to `store.dispatch`
const mapDispatchToProps = dispatch => {
// calling this is like calling `store.dispatch(login(...params))`
login: bindActionCreators(login, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Login);
This connect function will take these two functions as parameters. You can now import this connected container and use it with the functions "bound" to it as properties.
Example component below.
export default class Login extends Component {
static propTypes = {
// properties below come from connect function above.
currentUser: PropTypes.shape({
name: PropTypes.string.isRequired,
}).isRequired,
login: PropTypes.func.isRequired,
};
state = { name: "" };
onChange = ({ target: { value: name } }) => this.setState({ name });
onSubmit = e => {
e.preventDefault();
login(this.state.name);
};
render() {
return (
<form onSubmit={this.onSubmit}>
<input
placeholder="name"
onChange={this.onChange}
value={this.state.name}
/>
</form>
);
}
}
Notice, you never had to reference the store.