Redux step to step - reactjs

i have this code from https://jsbin.com/zirugiteju/edit?js,console,output
but i have a question, what is {store.getState().todos} its in the bottom of the code, see please this part
const render = () => {
ReactDOM.render(
this is the code complete
const todo = (state, action) => {
switch(action.type) {
case 'ADD_TODO':
console.log("ADD");
return {
id : action.id,
text: action.text,
completed: false
};
break;
case 'TOGGLE_TODO':
if (state.id !== action.id ) {
return state;
}
return {
...state,
completed: !state.completed
};
break;
default:
return state;
}
};
const todos = (state=[], action) => {
switch(action.type) {
case 'ADD_TODO':
return [
...state,
todo(undefined, action)
];
break;
case 'TOGGLE_TODO':
return state.map(t =>todo(t, action));
break;
default:
return state;
}
};
const visibilityFilter = (state='SHOW_ALL', action) => {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.filter;
break;
default:
return state;
}
};
const { combineReducers } = Redux;
const todoApp = combineReducers({
todos,
visibilityFilter
});
const { createStore } = Redux;
const store = createStore(todoApp);
const { Component } = React;
let nextTodoId = 0;
class TodoApp extends Component {
render() {
return (
<div>
<input ref={node => {
this.input = node
}} />
<button onClick={()=>{
store.dispatch({
type: 'ADD_TODO',
text: this.input.value,
id : nextTodoId++
});
this.input.value = '';
}}>
Add Todo</button>
<ul>
{this.props.todos.map(todo =>
<li key={todo.id}>
{todo.text}
</li>
)}
</ul>
</div>
);
}
}
const render = () => {
ReactDOM.render(
<TodoApp
todos={store.getState().todos}
/>,
document.getElementById('root')
);
};
store.subscribe(render);
render();

The prop todos = {store.getState().todos} that you are passing to TodoApp component is a reducer, called todos, from your redux state that you combined in this part of the code:
const todoApp = combineReducers({
todos,
visibilityFilter
});
The getState() function returns the current state tree of your application. It is equal to the last value returned by the store's reducer.
You can learn more about redux States in this link: https://redux.js.org/api/store

Related

React/Redux: Why blog app is not removing the items?

I have created a simple blog app using react and redux, right now only two functionalities are present in the app -> rendering and deleting blogs. Rendering is working fine but not the delete one.
Most likely, the issue will be in the reducer of my application. Please Suggest.
Here's my whole code.
sandbox link: https://codesandbox.io/s/testing-75tjd?file=/src/index.js
ACTION
import { DELETE_BLOGS, GET_BLOGS } from "./actionTypes";
// for rendering list of blogs
export const getBlog = () => {
return {
type: GET_BLOGS,
};
};
// for deleting the blogs
export const deleteBlogs = (id) => {
return {
type: DELETE_BLOGS,
id,
};
};
REDUCER
import { DELETE_BLOGS, GET_BLOGS } from "../actions/actionTypes";
const initialState = {
blogs: [
{ id: 1, title: "First Blog", content: "A new blog" },
{ id: 2, title: "Second Blog", content: "Just another Blog" },
],
};
const blogReducer = (state = initialState, action) => {
switch (action.types) {
case GET_BLOGS:
return {
...state, // a copy of state
};
case DELETE_BLOGS:
return {
...state,
blogs: state.filter((blog) => blog.id !== action.id),
};
default:
return state; // original state
}
};
export default blogReducer;
COMPONENT
import React, { Component } from "react";
import { connect } from "react-redux";
import { deleteBlogs } from "../actions/blogActions";
class AllBlogs extends Component {
removeBlogs = (id) => {
console.log("removeBlogs function is running with id", id);
this.props.deleteBlogs(id); // delete action
};
render() {
return (
<div>
{this.props.blogs.map((blog) => (
<div key={blog.id}>
<h3>{blog.title}</h3>
<p>{blog.content}</p>
<button onClick={() => this.removeBlogs(blog.id)}>delete</button>
<hr />
</div>
))}
</div>
);
}
}
const mapStateToProps = (state) => ({
blogs: state.blogs,
});
export default connect(mapStateToProps, { deleteBlogs })(AllBlogs);
ISSUE
You were sending action key type and receiving as action.types in reducer
SOLUTION
const blogReducer = (state = initialState, action) => {
switch (action.type) { // change `types` to `type`
case DELETE_BLOGS:
return {
...state,
blogs: state.blogs.filter((blog) => blog.id !== action.id)
};
default:
return state; // original state
}
};

React - ContextAPI not setting correct state

I wonder what I am doing wrong here. The dispatch methods are dispatching correct values but the state object is showing wrong values.
{ name: "name", room: "room" } is what I am dispatching separately. But the state is showing { name: "room": room: "" }
Google chrome logs :
NOTE: please checkout the code here from the github repo incase needed.
Reducer:
export const initialState = {
name: '',
room: ''
}
export const reducer = (state, action) => {
console.log("Calling action", action);
switch (action.type) {
case types.SET_NAME:
return { ...state, name: action.name }
case types.SET_ROOM:
return { ...state, name: action.room }
default:
return state;
}
}
_app component:
import DataProvider from "../context/DataProvider";
import { initialState } from '../reducers/index';
import { reducer } from '../reducers';
const AppComponent = ({ Component, pageProps }) => {
return (
<DataProvider intialState={initialState} reducer={reducer}>
<Component {...pageProps} />
</DataProvider>
)
}
AppComponent.getInitialProps = async (appContext) => {
let pageProps = {};
if (appContext.Component.getInitialProps) {
pageProps = await appContext.Component.getInitialProps(appContext.ctx);
}
return { pageProps }
}
export default AppComponent;
Component:
const Join = () => {
const [name, setName] = input('');
const [room, setRoom] = input('');
const [state, dispatch] = useContext(DataContext);
const submit = (e) => {
if (name === '' || room === '') {
e.preventDefault();
return;
}
dispatch({
type: types.SET_NAME,
name
});
dispatch({
type: types.SET_ROOM,
room
});
}
return (
<div>
<h1>Join</h1>
<input onChange={(e) => setName(e)} placeholder="name" />
<input onChange={(e) => setRoom(e)} placeholder="room" />
<Link href="/chat">
<button type="submit" onClick={(e) => submit(e)}>Submit</button>
</Link>
</div>
)
}
Chat component (where I am consuming state):
const Chat = () => {
// const backendEndpoint = 'http://localhost:5000';
const [state, dispatch] = useContext(DataContext);
console.log('STATE', state)
return <h1>Chat</h1>
}
Chat.getInitialProps = async (ctx) => {
return {}
}
export default Chat;
I think the problem is in your reducer
case types.SET_ROOM:
return { ...state, name: action.room }
Here you change the name in rooms action
maybe you need to update like this
return { ...state, room: action.room }
actually u make a mistake in your Reducer.js
export const reducer = (state, action) => {
console.log("Calling action", action);
switch (action.type) {
case types.SET_NAME:
// equals state.name = action.name
// state = { name: 'name', room: '' }
return { ...state, name: action.name }
case types.SET_ROOM:
// equal state.name = action.room
// state = { name: 'room', room: '' }
return { ...state, name: action.room }
default:
return state;
}
}
// u can change your code style to reduce mistakes
export const reducer = (state, action) => {
const {name, room} = action
switch (action.type) {
case types.SET_NAME:
return { ...state, name }
case types.SET_ROOM:
return { ...state, room }
default:
return state;
}
}

React input field not updating when props passed

I am using redux for simple POC. I am passing props to component. However when I assign it to input box, the input box is not updating.
My component code:
CurrenctConverter.js
handleAmountchange(e) {
debugger;
var payload = e.target.value
store.dispatch({ type: "Add", val: payload })
}
render() {
return (
<div>
Currency Converter
USD <input type="text" onChange={this.debounceEventHandler(this.handleAmountchange, 1000)} value={this.props.globalstate.val}></input> **this inputbox not working**
INR <input type="text"></input>
<input type="button" value="Convert"></input>
</div>
)
}
redux store:
I am getting props from this store
import React from 'react'
import { createStore } from 'redux'
var initialstate = {
val: 100
}
const MyReducer = (state = initialstate, action) => {
if (action.type = "Add") {
return {
...state,
val: action.val
}
}
return state;
}
var mystore = createStore(MyReducer);
export default mystore;
In the reducer, please update the code as
var initialstate = {
val: 100
}
const MyReducer = (state = initialstate, action) => {
switch (action.type) {
case 'Add':
let updatedState={
...state,
val: action.val
}
return updatedState;
default:
return state;
}
var mystore = createStore(MyReducer);
export default mystore;

componentDidUpdate not firing after redux state change

I have these Reducers:
const initialState = {
categories: [],
programms: {}
}
export const programmReducers = (state = initialState, action) => {
let programms = state.programms;
switch (action.type) {
case actionTypes.FETCH_CATEGORIES:
return Object.assign({}, state, {
categories: action.payload
})
case actionTypes.FETCH_PROGRAMM:
programms[action.payload.id] = action.payload;
console.log(programms);
return {
...state,
programms: Object.assign({}, programms)
}
case actionTypes.FETCH_PROGRAMM_COMPONENTS:
programms[action.programmId].components = action.payload;
console.log('Added Components')
return {
...state,
programms: programms
}
default:
return state
}
}
The last one (FETCH_PROGRAMM_COMPONENTS) adds an array to an object in the programm object. This works but somehow it won't fire componentDidUpdate in my component. It works for FETCH_PROGRAMM though.
class ProgrammPage extends Component {
static async getInitialProps({ store, query: {id} }) {
let programm;
if (!store.getState().programm.programms[id]) {
console.log('Programm not! found');
programm = await store.dispatch(loadProgramm(id));
await store.dispatch(loadProgrammComponents(id));
} else {
programm = store.getState().programm.programms[id];
console.log('Programm found')
}
return {
// programm: programm
programmId: id
}
}
componentDidUpdate(prevProps) {
console.log('UPDATE', this.props, this.props.programm.components.length)
if (!prevProps.user && this.props.user) {
this.props.loadProgrammComponents(this.props.programmId);
}
}
render() {
return (
<div>
<h1>Programm</h1>
<h2>{this.props.programm.name}</h2>
<h2>{this.props.programm.id}</h2>
<h3>Components: {this.props.programm.components ? this.props.programm.components.length : 'None'}</h3>
<br></br>
<h1>User: { this.props.user ? this.props.user.uid : 'None'}</h1>
<button onClick={() => this.props.loadProgramm('ProgrammLevel2')}>Load Programm</button>
<button onClick={() => this.props.loadProgrammComponents(this.props.programmId)}>Load Components</button>
</div>
)
}
}
function mapStateToProps(state) {
return {
programm: state.programm.programms['ProgrammLevel1'],
programms: state.programm.programms,
user: state.auth.user
}
}
const mapDispatchToProps = dispatch => bindActionCreators({
loadProgrammComponents,
loadProgramm
}, dispatch)
export default connect(
mapStateToProps,
mapDispatchToProps
)(ProgrammPage)
You returning the same reference.
Try returning a copy of programms array: [...programms] ( or Object.assign() if it's an Object).
case actionTypes.FETCH_PROGRAMM_COMPONENTS:
programms[action.programmId].components = action.payload;
console.log('Added Components')
return {
...state,
programms: [...programms] // <-- Return new state
}

Failed prop type issue

I have the following structure:
and a TodoList component as follow:
import React from 'react'
import PropTypes from 'prop-types'
import Todo from './Todo'
const TodoList = ({ todos, onTodoClick }) => (
<ul>
{todos.map( (todo, i) => (
<Todo key={i} {...todo} onClick={() => onTodoClick(todo.id)} />
))}
</ul>
)
TodoList.propTypes = {
todos: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
completed: PropTypes.bool.isRequired,
text: PropTypes.string.isRequired
}).isRequired
).isRequired,
onTodoClick: PropTypes.func.isRequired
}
export default TodoList
I am getting the following error:
this is my index in the reducers folder:
import { combineReducers } from 'redux'
import {
ADD_TODO,
TOGGLE_TODO,
SET_VISIBILITY_FILTER,
VisibilityFilters
} from '../actions/index'
const { SHOW_ALL } = VisibilityFilters
function visibilityFilter(state = SHOW_ALL, action) {
switch (action.type) {
case SET_VISIBILITY_FILTER:
return action.filter
default:
return state
}
}
function todos(state = [], action) {
switch (action.type) {
case ADD_TODO:
return [
...state,
{
text: action.text,
completed: false
}
]
case TOGGLE_TODO:
return state.map((todo, index) => {
if (index === action.index) {
return Object.assign({}, todo, {
completed: !todo.completed
})
}
return todo
})
default:
return state
}
}
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
The onTodoClick doesn't fire either in TodoList and it's defined here:
import { connect } from 'react-redux'
import { toggleTodo } from '../actions/index'
import TodoList from '../components/TodoList'
const getVisibleTodos = (todos, filter) => {
switch (filter) {
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
case 'SHOW_ALL':
default:
return todos
}
}
const mapStateToProps = state => {
return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}
const mapDispatchToProps = dispatch => {
return {
onTodoClick: id => {
dispatch(toggleTodo(id))
}
}
}
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList)
export default VisibleTodoList

Resources