Adding Storybook knobs in React Hooks app with Redux - reactjs

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(...);

Related

Using Redux dev tools with NextJS: how to find out what's going on in store when Redux is being called server side?

We have a NextJS application using next-redux-wrapper and Redux thunks. We have a page that works fine when we load the page via a local link, that is, it's rendered locally, but when we reload the page, thus rendering it on the server, our store remains (partially) empty: certain fields are never filled.
I'm using Redux dev tools to follow the actions, but all I ever see when I reload the page in the list of actions is ##init. When I put log statements in I see -- in the server-side console -- that my reducer is being called with valid values. However that field remains empty in the store, as shown by RDT in the browser.
The Redux actions are not showing up in the browser Redux Dev Tools console because they are happening on the server.
The store is set up as next-redux-wrapper instructs
// _app.ts
import withRedux from 'next-redux-wrapper';
import initStore from '../redux/store';
const makeStore = initialState => {
return initStore(initialState);
};
const MyApp = ({ Component, pageProps, apollo, store }: Props) => {
return (
<ApolloProvider client={apollo}>
<Provider store={store}>
<Sidebar />
<Component {...pageProps} />
</Provider>
</ApolloProvider>
);
};
MyApp.getInitialProps = async appContext => {
const { Component, ctx } = appContext;
const appProps = await App.getInitialProps(appContext);
const pageProps = Component.getInitialProps
? await Component.getInitialProps(ctx)
: {};
const allProps = {
...appProps,
...pageProps
};
return { ...allProps };
};
export default withRedux(makeStore)(withApollo(MyApp));
How can I figure out what's happening in my Redux store if I can't use Redux Dev Tools to see? What I'd like to do is find out exactly where and when the values that are being passed to the reducers are overwritten with a blank value.
The answer turned out to be that I was dispatching a thunk within my thunk server side, and I suppose that the result didn't come back in time to make it to the store transfer from NextJS server to the client. When I made it a direct, async, call within my thunk, all worked fine.

Using React-Redux: How to Access Variables in the Store, within Nested Components

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.

Where to initialize store when using connect in react-redux project

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.

ReactJS + Redux subscribe method mess

Using create-react-app
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
// Box.js which gets rendered in App.js
import {store} from '../../../index'
...
const renderagain = () => store.getState()
store.subscribe(renderagain)
...
This throws me an error
TypeError: Cannot read property 'subscribe' of undefined
Excuse me? What am I doing wrong?
It's a circular dependency issue.
index.js imports App.js, which eventually imports Box.js. But, Box.js is attempting to import {store} from "../../index.js", which is wrong in several ways.
Your component files should not be attempting to import the store directly, and definitely should not be attempting to import values from index.js. You also shouldn't be trying to subscribe to the store directly in your component files.
Instead, use the React-Redux connect() function in your components to create wrappers that manage the process of subscribing to the store for you. Then, use the connected components, and they'll automatically use the store you passed to <Provider>.
//index.js
...
export const store = createStore(getChange, applyMiddleware(thunk))
//getChange is my reducers name
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.getElementById('root'));
registerServiceWorker();
the code above is good to be used to create a store with some reducers combined. and also providing that tot he whole application by passing it into the Provider Component wrapping the Application. This makes the redux actions and store contents available to access for the component. There you can subscribe the store to et notified on changes in store, or on action dispatches.
You are using the callback to subscribe in a wrong way. You might use it this way:
function select(state) {
return state.some.deep.property
}
​
let currentValue
function handleChange() {
let previousValue = currentValue
currentValue = select(store.getState())
​
if (previousValue !== currentValue) {
console.log(
'Some deep nested property changed from',
previousValue,
'to',
currentValue
)
}
}
​
const unsubscribe = store.subscribe(handleChange)
unsubscribe()
For further documentation and queries you can see this. https://redux.js.org/api/store#subscribe-listener

JEST testing on redux is not working as expected

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>

Resources