hello world reducer for react/redux - reactjs

There are a few other hello world app questions with regard to react, but mine is specific to the reducer. Im not exactly sure what I should put in the reducer for my specific action.
Note*: I thought maybe i need to add a message: "" key value pair to my initial state and then declare a
var newState = Object.assign({}, state, {
message:"hello world"
});
into my if statement in the reducer, then dispatch it in the component, but that seems unneccesary since it should always print hello world, so hard coding seems more efficient. Hopefully there isn't too much clutter in this question as well.
Here is my component:
var HelloWorld = React.createClass({
helloWorld: function() {
this.props.dispatch(actions.printHello());
},
render: function() {
return (
<div className="HelloWorld">
<h1>Hello World!</h1>
</div>
);
}
});
var Container = connect()(HelloWorld);
module.exports = Container;
my action:
var $ = require("jquery")
var PRINT_HELLO = 'PRINT_HELLO';
var printHello = function() {
return {
type: GUESS_NUM
};
};
exports.PRINT_HELLO = PRINT_HELLO;
exports.printHello = printHello;
and reducer:
var actions = require('./actions');
var initialRepositoryState = {
type: null
};
var capstoneApp = function (state,action) {
state = state || initialRepositoryState;
if (action.type === actions.PRINT_HELLO) {
var newState = Object.assign({}, state, {
message:"hello world"
});
return newState;
}
};
I don't think you will need my index.js but I will provide if necessary.
Thanks in advance for input!

The reducer holds your state. So the way of thinking about it is "what are the parts of my program that can change?" And then from there, the next question is "What is the minimal amount of state needed to hold on to my program?"
From looking at your example, I get the impression that you are trying to build an application that sometimes displays "hello world" in the UI. Let me make a few more interactions to help describe all the pieces.
Initially, I'll help you create a program that has an empty label and a button. When you click on the button, it will display "hello world".
Okay, so to answer the first question: What can change? The app can either display "hello world" or nothing. We could store that in a couple of different ways. If the string is hard-coded, like you've alluded to above, then really you have a bool of show the message, or not.
And to the second question: one truthy value is pretty much the definition of a minimal state. So let's make a reducer:
var initialState = {
showMessage: false,
};
var reducer = function(state, action) {
var newState = Object.assign({}, state);
if (action.type === 'BUTTON_PRESS') {
newState.showMessage = !newState.showMessage;
}
return newState;
}
Okay, so now we've created a reducer that, when it gets the BUTTON_PRESS action, it flips the bit of its state.
Now, let's talk about how to hook that reducer up to redux. Right now, the reducer is a plain javascript function. We just need to pass that store into redux with the initial state. [createStore][1]
P.S. I normally write ES2015 code so there may be small typos in the commonJS import syntax
var redux = require('redux');
var store = redux.createStore(reducer, initialState);
The next part is to look at redux-react.
Redux-react is glue that works both ways in react. It connects data from the redux store to react props, and it connects react callbacks (such as a click) to redux actions.
So conceptually, it looks like this. You have a react component that has a button. When you click the button, we want to generate a 'BUTTON_PRESS' action. After this, your react component no longer cares what happens to BUTTON_PRESS. Its job is done. BUTTON_PRESS could do one of infinite things. Now, assume that redux-react does its job and gets the action passed to the reducer. The reducer computes its new logic and returns a new state. This new state has the value of showMessage. Then, redux-react does the other half of connecting and makes showMessage a prop for the component. Just to be clear, there is no explicit reason why the same react component has to respond to the state changed by your action. They could be different components.
To put it into bullet points, here is how the codeflow should work:
We create an initial store with showMessage = false
When creating the React component, we use connect to bind the showMessage to a prop, and to handle onClick of the button in the component to generate a 'BUTTON_PRESS' action.
Since showMessage is false, there is originally only a button present.
The user presses the button. React calls into the onClick handler
We use redux-react to dispatch a BUTTON_PRESS event
When redux gets an action, it calls the reducer with the current state and the action. The reducer is responsible for generating a new state in response to this action
The reducer sets showMessage to true
redux-react listens to store changes and when it changes it modifies the prop for the react component
The prop changes so react calls render()
Inside your render method you see that this.props.showMessage is true, so you display the message.
And here is how such a react component could be implemented. There are enough differences between React components in ES5 vs ES2015 that I'm just going to give you the ES2015 version and apologize again.
class HelloWorld extends Component {
render() {
const message = this.props.showMessage ? "Hello world!" : "";
return (
<div id="label">{message}</div>
<div id="button" onClick={this.props.handleOnClick}>Toggle the message </div>
);
}
}
HelloWorld.propTypes = {
showMessage: PropTypes.bool.isRequired,
handleOnClick: PropTypes.func.isRequired,
};
const mapStateToProps = state => ({
showMessage: state.showMessage,
});
const mapDispatchToProps = dispatch => ({
handleOnClick: dispatch({ type: 'BUTTON_PRESS', payload: '' })
});
export default connect(mapStateToProps, mapDispatchToProps)(HelloWorld);
You can keep reading the docs but I hope that helps explain what all the parts are. Let me know if anything isn't clear.
[1]: http://redux.js.org/docs/api/createStore.html

Related

How update array in real time not after refresh page (Redux)

I'm doing to do list and want do the functional when you click on button "done" the text will be crossed out.
I done array with deals which have fields 'text' and 'isDone'. isDone by default is false, when on click I get all array with deals and text deal in which you click. Than I map array with deals that I get and compare text from click deal and text in all deals in array.If they the same I change isDone from false to true.
But it update if i refresh the page and I need that it updata on click.
I use redux-persist and all states put into localStorage
button
<button onClick={()=>this.props.done(this.props.deals,value.text)}>Done</button>
Action
export function done(newDeals,dealText){
return(dispatch) =>{
newDeals.map(value=>{
if(value.text === dealText){
value.isDone = !value.isDone
}
})
dispatch(doneDeal(newDeals));
}
}
export function doneDeal(newDeals){
return{
type: DONE,
newDeals
}
}
Reducer
export default function toDoList(state = initialState, action){
switch(action.type){
case DONE:
return {
...state, deals: action.newDeals
}
default:
return state
}
}
I delete code that have no sense for this example, but need more info please ask I will tell
Thank you!
You have to use mapStateToProps to get the recently updated state from Redux state.
All what you need is to wrap your component export with the following:
const mapStateToProps = state => ({
deals: state.deals
});
export default connect(mapStateToProps)(ComponentName);
By this you are getting the needed state data from the initialState you have defined in your reducer and the reference to these data is the "deals" which can be used as normal prop: this.props.deals in case of class component OR as parameter through descructureing ({deals}) in case of functional component.
I don't know the full structure of the component because you haven't added it but this is the correct way to get the state from redux.
To make things more clear for you, you can read more through this link:
https://react-redux.js.org/using-react-redux/connect-mapstate
UPDATE: I figured out your problem after adding your reply.
The problem is with your code here:
<button onClick={()=>this.props.done(this.props.deals,value.text)}>Done</button>
You are getting the deals directly from the Redux global state and when dispatching your action you are passing them directly in the dispatch method. So your component is not able to listen to any change happening to your component. You need to save the deals in your local state:
state = {
deals: this.props.deals
}
and change the onClick to the following:
<button onClick={()=>this.props.done(this.state.deals,value.text)}>Done</button>

When to use Dispatcher in React Application

I am facing some issue while using Dispatcher in ReactJS. So, I try to remove this dispatcher from the store and still store works well. Store properly hold my data and change event works well.
Now I am bit confusing to use dispatcher in our application.
Here is the code
MenuList is my component in which I call MenuStore.getMenuFromAPI() and after I also added onChange event of MenuStore.
class MenuList extends React.Component{
constructor(){
super();
this.state = {open:false, menuList:"",numbering:-1}
}
componentWillMount(){
var that = this;
MenuStore.getMenuFromAPI();
MenuStore.on("change", ()=> {
that.setState({menuList:MenuStore.getMenu()});
})
}
componentWillReceiveProps(nextProps){
if(nextProps.show!=this.props.show){
this.setState({open:nextProps.show});
}
}
render(){
const { classes } = this.props;
return (
<div>My MEnu</div>
)
}
}
MenuStore
class MenuStore extends EventEmitter {
constructor() {
super();
this.menu = null;
}
getMenu(){
return this.menu;
}
getMenuFromAPI(){
var that = this;
$.ajax({
type: "POST",
url: LinkConstants.GETMENU,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
data: "",
dataType :"json",
success: function(response) {
that.menu =response;
that.emit("change");
}.bind(this),
error: function(xhr, status, err) {
console.log(err);
}.bind(this)
});
}
// handleAction(action) {
// switch (action.type) {
// case ActionTypes.MENU: {
// this.getMenuFromAPI();
// break;
// }
// }
// }
}
const menuStore = new MenuStore;
//Dispatcher.register(menuStore.handleAction.bind(menuStore));
export default menuStore;
As you can see I commented out Dispatcher.register line and handleAction function.
Above code works properly fine but I wanted to know why to use Dispatcher over here ?
If I want to just store my data in the MenuStore and get it back from MenuStore on any of the component in the application. So it is necessary to use dispatchers and action or to just work with stores only.
Please clarify my doubts with proper example or case scenario (if possible) when to use dispatchers and action or when to work with stores only.
In your example your are not using Redux at all, you've just created a class that is used as a simple storage for the fetched data but your are not using any of Redux capabilities.
Redux is all about one store which is just a plain object which represents your application state tree. In order to change this state you dispatch actions. Actions are just simple objects which describe what happened. Each action has a type field which describes the action. Actions are treated by reducers which are functions that gets the current state and the dispatched action and decide on the next state of the application. This is Redux in few sentences.
Redux store has a method named dispatch which is used to dispatch actions. As mentioned in Redux documentation, this is the only way to trigger a state change.
Lets say we have a TODO list application. Our store may be represented as an array of strings (todo items).
To add a new item to the list we will define a simple action:
const addItemAction = (item = '') => ({
type: 'ADD_ITEM',
data: item,
});
Dispatching this action can be done from within one of your component's methods which will be attached to some keyboard/mouse event:
class TodoList extends React.Component {
...
// addNewItem is called with a value from a text field
addNewItem(item) {
store.dispatch(addItemAction(item));
}
...
}
As I mentioned above, state is changed by a reducer function. The reducer decides if to change the state and how to change it. If dispatched action shouldn't change the state it can just return the received state:
function todoReducer(state = [], action) {
switch(action.type) {
case 'ADD_ITEM':
return [...state, action.data];
break;
default:
return state;
}
}
Reducer is passed to createStore method:
import { createStore } from 'redux'
const store = createStore(todoReducer);
In the TodoList component you can subscribe to the store using store.subscribe method which accepts a callback function that will be called each time the store state changes. When detecting a change you can call setState of your component to set the list on the component state and to cause the component to rerender:
class TodoList extends React.Component {
....
componentDidMount() {
this.storeSubscription = store.subscribe((state) => {
// For the example I'm just setting the state (list of todos)
// without checking if it changed or not
this.setState({
todos: state,
});
});
}
render() {
return this.state.todos.map(todo => <div>{todo}</div>);
}
....
}
This is an almost complete example of using Redux. We used action to describe an event in our application, we used the store's dispatch method to dispatch the action to the store, Redux will invoke the reducer when it gets new actions, the reducer computes the new state and our component detects the change by using the store's subscribe method.
There are more things to consider and to take care of in a more complex application. You will probably have a more complex state tree so you will need additional reducers to take care of computing the state. Additionally in some step you would need to consider working with some helpers to reduce overhead of subscribing to state change and detecting changes.
In a more complex application you would probably connect your component to the store by a binding library such as react-redux so your component will receive the relevant parts of the store by props which will save the overhead of subscribing to the store changes and deciding on when to rerender the component.
I would recommend watching "Getting started with Redux" by Dan Abramov to get some more understanding of what is Redux and how to work with it.
Getting started with Redux

immutable react reducer state is not updating

I am trying to create a simple website using react-redux and the immutable-assign library (instead of immutable) to handle my state. (documentation for immutable-assign: https://github.com/engineforce/ImmutableAssign)
I've made solutions with both the 'immutable' and 'immutable-assign' libraries, but neither work (code for immutable solution is commented out in the reducer below. No matter which changes I make, the state never changes, and the values are never assigned to menuItems
The setMenu(newMenu) function is currently called with dummydata in the form of a list of arrays in the following format:
menuItems: {
id: "113",
foodItem: "tesatewr",
description: "gfdgsdfsdf",
price: 999
}
The reducer:
import { iassign } from 'immutable-assign'
export function setMenu(newMenu) {return {type: 'SET_MENU_ITEMS', newMenu}}
const initialState = {
date: 'test',
menuId: 'test',
menuItems: []
}
function menuViewReducer(state = initialState, action){
switch(action.type){
case 'SET_MENU_ITEMS':
var itemList = iassign(
state,
function (n) { n.push('testtest'); return n}
)
return state.set(['menuItems'], itemList)
default:
return state
}
}
/* CODE FOR IMMUTABLE
function menuViewReducer(state = fromJS(initialState), action){
switch(action.type){
case 'SET_MENU_ITEMS':
return state.updateIn(['menuItems'], (menuItems) => menuItems.push(fromJS(action.newMenu.menuItems)))
default:
return state
}
} */
export const menuSelector = {
date: state => state.menuViewList.date,
menuId: state => state.menuViewList.menuId,
menuItems: state => state.menuViewList.menuItems
}
export default menuViewReducer
Render function:
render(){
return (
<div>
Test data here: {this.props.menuItems}
<ul className="menuViewList">{ this.mapMenuItemsToListElements() }</ul>
<button
onClick={() => this.mapMenuItemsToListElements()}> get data
</button>
</div>
)
}
It's really hard to figure out what's not working from this code. The best I can do is give you some debugging tips:
First off, are you getting any errors? If yes, that seems like a good place to start.
Otherwise, try to narrow down where the problem is occurring.
Are you sure your reducer is actually getting called?
I would try putting a console.log right after your case 'SET_MENU_ITEMS': so you know when your code is being run.
If it's not:
The problem could be a number of things:
Your reducer isn't connected to your store properly
You're not properly dispatching actions to your store
The actions you're dispatching don't have their type property properly set.
If it is:
The problem could be a number of different things. Some that I can think of:
Your state isn't being updated (properly). Try logging the state at the start of your reducer and your new state right before you return it. Or consider using redux-devtools to inspect your state.
Your view isn't getting updated. Maybe your component isn't connected to your store properly.
I found the error and as Simon pointed out, its hard to find from my submitted code.
I was calling setMenu(newMenu) in a generator function, so I should have called it like this:
yield put(setMenu(newMenu))
instead of
setMenu(newMenu)

How to wait for an action to complete?

I'm new to react and redux and have been exploring how it is different from angular.
I'm trying to do a simple login page and am not able to achieve what I want. Once I get the username and password from a login form, I submit it like below :
submitHandler(e){
e.preventDefault();
var user = {
name : this.state.username,
password: this.state.password
}
this.props.authenticateUser(user);
browserHistory.push('/home');
this.setState({
username:'',
password:''
})
}
Here, authenticateUser is a function inside my reducer (shown below) which checks from an already existing user's list and then the state with a property isAuthenticated :
case 'AUTHENTICATE_USER':
var users = state.userslist;
var payloadUser = action.payload;
for (let i = 0; i < users.length; i++) {
let user = users[i]
if (user.name === payloadUser.name) {
return {...state, isAuthenticated: true };
}
};
return {...state, isAuthenticated: false };
Now in Angular, I would just wait for this call to finish and check whether this value is true or false, and navigate to the home page using angular-router.
But how would I achieve the same in react. I am using react-router in my sample application.
I tried to check isAuthenticated in my submitHandler function right below where I call this.props.authenticateUser(user) , but the problem is , this.props.isAuthenticateUser is not updated and returns false, which I have set as the initialState in my reducer.
Please tell me how I can check isAuthenticated after the authenticateUser function has called so that I can proceed with my homepage routing. Do I have to use a promise and wait for the state to be updated by redux and then check it again ?? (I know react is a one way path and it doesn't work that way.)
Also if my authentication fails, how do I show an error panel below my login form. I think using a component for the error panel which takes in isAuthenticated as input and checking if false in order to show (ie. ngShow like in Angular.) But I'm afraid that will not work as well, since my state will not be updated just in time.
I know that the render function will be called with any change in state. But I just can't wrap my head around React clearly.
Edit: For brevity, I have not provided the action creators and the full reducer above rather shown only the switch case operation for authenticate user. My app follows the original redux architecture with actions, reducers, containers, components and such.
EDIT: Github link here
I will try to explain briefly how data flow works in a Redux application:
The reducer should not be called directly from the component. Your call to authenticate user should be inside an action and that is what should be dispatched from the component.
When you define the action, you can give a property to define the type of action it is. For example, in this case, it could be type: AUTHENTICATE_USER
After the completion of the action, the redux store calls the reducer where with the current state and the action. Here, the redux state can be updated based on action.type (the second code snippet above)
This is the most important part: your component needs to have a mapStateToProps method which passes values from your Redux state as props into your component. So as the state changes, the props get updated and the component re-renders. To use mapStateToProps, you need to implement connect from the react-redux library. (https://github.com/reactjs/react-redux/blob/master/docs/api.md#connectmapstatetoprops-mapdispatchtoprops-mergeprops-options)
To achieve what you want, this is what I suggest:
In your component's componentWillReceiveProps method, checking for props.isAuthenticated and using context.router.push() to navigate if the user is authenticated.
Also having a check based on props.isAuthenticated in the component's render method to show the error message.
A few links which could be useful:
https://redux.js.org/basics/data-flow
https://redux.js.org/basics/usage-with-react
I prefer code like this:
const mapStateToProps = (state) => {
return {
isAuthenticated: state.isAuthenticated
}
}
class Dashboard extends PureComponent {
render() {
const { isAuthenticated } = this.props
return (
<div>
{ isAuthenticated ? (
<div>
<p>Hello</p>
</div>
) : (
Login()
)}
</div>
)
}
}
Source: https://stackoverflow.com/a/56899814/3850405
Addition to the answer from #Nupur. componentWillReceiveProps() is considered unsafe and the method name now is: UNSAFE_componentWillReceiveProps()
https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
Use componentDidUpdate() instead if you would like this approach, this method is not called for the initial render.
componentDidUpdate(prevProps) {
if (this.props.isAuthenticated ) {
//perform code here
}
}
https://reactjs.org/docs/react-component.html#componentdidupdate

Accessing and setting state in an react/flux application

I'm working on a react app with a flux implementation.
I have a store which is bound to a component and in the ctor I set some default (blank) state values. In componentWillMount I populate the state by firing some actions which update the store data.
The store emits a change and the component handles that change by putting bits of the store data into state.
In my render method, I'm wanting the render to depend on the state data.
At the moment I have a couple of issues.
If in my render method I do something like this.state.MyThing.AProperty then the render method is called too early when MyThing hasn't been populated yet. This seems to occur in a lot of places where I want a render to use state data. Is there a sensible guard against this or am I doing this wrong?
I'm using a store to emit a change, and handling that change by getting data from the store and setting it to the state of the component. My thinking here is that if I set it as state then the component will know to re-render when the state changes. Is this correct? or should I be getting the data from the store in the emit handler and using it directly? or setting it to a local var in the component?
The reason I ask is that I seem to encounter issues with setState calls not being immediate and wanting to use state as soon as I set it. With this in mind it seems like I might be doing it wrong.
Any thoughts greatly appreciated.
If you use conditionals in your render, then you can guard against unpopulated data being rendered.
<div>
{typeof this.state.myThing == 'object' ?
<strong>this.state.myThing.aProperty</strong> :
<span>Nothing to see here</span>}
</div>
And with regards to your second question, yeah. That's totally fine and it's the expected way to work with Flux. You can even take inspiration from Redux & Co and make higher order components that map store state to props.
function connect(store, mapStateToProps, Component) {
return React.createClass({
getInitialState() {
const state = store.getState();
return { state };
},
componentWillMount() {
store.listen(state => this.setState({ state }));
},
render() {
const stateProps = mapStateToProps(this.state);
const passedProps = this.props;
const props = Object.assign({}, stateProps, passedProps);
return <Component {...props} />;
}
});
}
This pattern allows you to take an existing component and wrap it in a container that will re-render whenever the store changes, then use the mapStateToProps function to work out which props to pass down to your original component.
const MyStore = { ... };
const MyComponent = React.createClass( ... );
function mapStateToProps(state) {
return { foo: state.bar.foo };
}
export default connect(MyStore, mapStateToProps, MyComponent);
setState is an asychronous method as it needs to be batched to keep React apps from being delaying repaints when they trigger lots of updates. You can reliably wait for the state to change by passing a callback as the second argument.
this.setState({ foo: 'bar' }, () => this.state.foo);

Resources