How do i pull data from redux state in react - javascript

Im trying to make an api request from redux then take that data and put it in my react state (arrdata). The api call works but i cant seem to get the state on my app.js to update based on the redux api call. Am i missing something?
App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
arrdata: []
};
}
componentDidMount() {
this.props.loadData();
console.log(this.props.data);
}
render() {
const {arrdata} = this.state
return ( ......)}}
const mapStateToProps = state => {
return {
data: state.data
};
};
export default connect(mapStateToProps, dataAction)(App);
Action
export function loadData() {
return dispatch => {
return axios.get("https://api.coincap.io/v2/assets").then(response => {
dispatch(getData(response.data.data.slice(0, 10)));
});
};
}
export function getData(data) {
return {
type: "GET_DATA",
data: data
};
}
Reducer
let initialState = {
data: []
};
const mainReducer = (state = initialState, action) => {
if (action.type === "GET_DATA") {
return {
...state,
data: action.data
};
} else {
return {
...state
};
}
};
export default mainReducer;

I think you are misleading store with state. Your arrdata is empty since it's stored inside state, but your data comes from props.
Anyways, arrdata in state remains empty, since you are not setting the state anywhere. To do that, you would have to use e.g. getDerivedStateFromProps lifecycle hook, however I wouldn't recommend that.
render() {
const { data } = this.props;
console.log(this.props.data);
return (
// do something with your data
);
}
It should log your data properly.
Note: You don't need state, actually. It's a better approach to manipulate over props, instead of saving data from props into state (in most cases).

Related

React UI doesn't update on redux store change

I have a redux State HOC to manage the connection
I Have a problem when I add a new post to the store
import React, { useEffect } from "react";
import { connect } from "react-redux";
export default function withState(WrappedComponent) {
function mapStateToProps(reduxState) {
let state = {};
for(let t of Object.entries(reduxState)) {
state = {...state, ...t[1]}
}
return {
...state,
};
}
return connect(
mapStateToProps,
null
)(function (props) {
useEffect(() => {}, [props.posts, props.comments]) /*tried this but didn't work*/
return (
<React.Fragment>
<WrappedComponent {...props} />
</React.Fragment>
);
});
}
I am trying to make the program render the response from my back-end without me reloading the page manually
I tried using the useEffect
and I saw through the dev tools that the state change correctly
my reducer
import { GET_ALL_POSTS, CREATE_NEW_POST } from "../actions"
const initialState = {
posts: []
}
export default function postReducer(state = initialState, action) {
let newState = {...state}
switch(action.type){
case GET_ALL_POSTS:
return {
...newState,
posts: [...action.posts],
}
case CREATE_NEW_POST:
const posts = [...newState.posts, action.post]
return {
...newState,
posts
}
default:
return {
...newState,
}
}
}
I also read that react changes doesn't respond to shallow copies so I changed the whole array in the post reduces when I add a new post
Your withState HOC is very strange. I'm not sure why you don't just use connect directly (or use hooks). But try this:
export function withState(WrappedComponent) {
return connect(
(state) => ({
posts: state.postsReducer.posts,
comments: state.commentsReducer.comments
}),
null
)(WrappedComponent);
}

React-Redux Transform data to props

I'm implementing a Task App where I have two views to render Tasks and Items and one where I render multiple lists based on the Task Status as kanban board.
My reducer:
export const rootReducer = Redux.combineReducers({
Tasks: TasksReducer,
itemsAreLoading: itemsAreLoadingReducer
});
const TasksReducer = (state , action ) => {
if (typeof state == "undefined") {
console.log('state undefined');
return null;
}
switch (action.type) {
case TasksTypes.Tasks_GET:
return action.Tasks;
default:
console.log(state);
return state;
}
}
export class TasksApp extends React.Component {
constructor(props) {
super(props);
}
render() {
const {tasks} = this.props;
return (<div>
<ItemsView Tasks={tasks}/>
<BoardView Lanes=[/* tasks tranfromed into mutliple list based on their status*/]/>
</div>);
}
}
const mapStateToProps = (state) => {
return {
tasks: state.Tasks
};
};
My Question is where to transform the data for the second view to have a different representation of the data.
The main problem here is that you dont fire any actions in your class, and I dont see any actions here neither. So first, you have to fire an action, and dispatch it with the type and payload, second, as David Tyron wrote, the syntax was a bit off in this line:
const { tasks } = this.props;
And for the end a small remark, you can do some destruction in the mapStateToProps function:
const mapStateToProps = ({ Tasks }) => {
return { Tasks };
};
And then get it like const { Tasks } = this.props;
I think, that the best practice to change your tasks props is to fire another action that creates a new props from your tasks props, something like:
export const transformData = tasks => {
return dispatch => {
//Do the transformations here
dispatch {
type: TRANSFORM_DATA,
payload: transformed_tasks
}
}
}
And then catch it with a reducer.
And IMHO, the best place to call this action is the componentDidMount()

MapStateToProps not working

I am trying to use redux with react. The mapStateToProps is not called.
The dispatch calls are working properly, the action reaches the reducer and the newState is returned and the state of the store is modified. But mapStateToProps is not called and the component is not rerendering.
class Wrapper extends React.Component {
updateChartData (data) => {
...logic...
this.props.actions.chartDataAction(modifiedData);
}
}
function mapStateToProps(state, ownProps) {
return {
chartData: state.chartData
};
}
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(chartDataAction, dispatch)
};
}
export default connect(mapStateToProps, mapDispatchToProps)(Wrapper);
The other classes that use updated state is as follows
class Chart extends React.Component {
render(){
/*console.log(this.props.chartData);*/
}
}
function mapStateToProps(state, ownProps) {
console.log(state);
return {
chartData: state.chartData
};
}
let ChartComponent = withStyles(styles)(Chart);
export default connect(mapStateToProps)(ChartComponent);
The action is as follows
export default function (state = [], action) {
if (action.type === actionTypes.CHANGE_CHARTDATA) {
return action.chartData;
} else {
return state;
}
}
The reducer is
export default function (state = [], action) {
if (action.type === actionTypes.CHANGE_CHARTDATA) {
return action.chartData;
} else {
return state;
}
}
I've even checked using redux dev tools. The chartData is being updated in the redux store. The chartData is properly passed to the Chart class and it renders on the first update. On consecutive dispatching, the chartData is updated in the redux store, but the mapStateToProps of Chart class is not called and the Chart class is not rerendering.
UPDATE:
I'm trying to live update the chart and it does not render if the few entries in the chartData array are changed.
I noticed that the chart component rerenders when the whole chartData is changed. But I want it to rerender if any part of the chartData is changed.
Edit : Be sure to follow the immutable update patterns even outside of your reducer (in updateChartData() method in your case).
You are probably mutating data in your "...logic...", you can use immutable-js to make it easier for you.

How to keep state when switch the component in Reactjs?

I have a component
class App extends React.Component {
constructor(props) {
super(props);
this.state = {stories: []};
}
componentDidMount() {
$.get(Api.getList(), (result) => {
const data = result;
if (data) {
this.setState((prevState) => ({
stories: data.stories
}));
}
});
}
render() {
if (this.state.stories.length == 0) {
return (
<Tpl>
<Loading/>
</Tpl>
);
} else {
return (
<Tpl>
<Stories stories={this.state.stories}/>
</Tpl>
);
}
}
}
and everytime when I switch to this component,
it will run constructor first.
so the state will be empty.
what I want is if stories had items, it don't need to get data again.
is it any method to keep that state?
I think the best way to achieve this would be to use react-redux whereby you have a centralized store which maintains state to all the components and thus saving it from refreshing everytime the component loads
Here is a good article to help you get started with redux.
The other way to do what you want is to have you states saved in localStorage whereby on every component load you load data from localStorage and set to state initially and when updating a state also update the value there. Below is a sample method that you can follow for this approach.
constructor(props) {
super(props);
var stories = JSON.parse(localStorage.getItem( 'stories' )) || null
this.state = {stories: stories};
}
componentDidMount() {
$.get(Api.getList(), (result) => {
const data = result;
if (data) {
JSON.stringify(localStorage.setItem( 'stories', data.stories));
this.setState((prevState) => ({
stories: data.stories
}));
}
});
}

React Redux mapStateToProps loads data in the second call

mapStatToProps is callings it's self twice and loads data on the second call but then doesn't assign it to components as a prop and returns an empty array.
The Reducer:
export default function postsReducer(state = initialState.posts, action) {
switch (action.type) {
case types.LOAD_POSTS_SUCCESS:
return action.posts;
default:
return state;
}
}
Here is my mpStateToProps func:
function mapStateToProps(state, ownProps) {
const singlePost = state.posts.filter(post => post.code == ownProps.params.id);
return {
post: singlePost
};
}
Here is my Component's state:
this.state = {
post: [...props.post]
};
Your code is probably right, but it seems like you forgot to update your state.post value when your component receives new props.
componentWillReceiveProps(nextProps) {
this.setState({
post: nextProps.post
});
}

Categories