I want to set 'username' in the state to the localstorage.getItem,but the problem is it is not working,Any suggestions?
class ToDoApp extends Component {
state = {
username:'',
inputValue: '',
todos: [],
currentPage: 1,
pageCount: 1,
itemsPerPage: 10,
};
Function with posts item to the data:
addItem = () => {
let {todos} = this.state
let userName = localStorage.getItem('username')
console.log(userName)
if (this.inpRef.current.value === '') {
return alert('We dont do that here....')
} else {
axios
.post(`http://localhost:8080/add`, {
username:userName,
todo: this.inpRef.current.value,
checked: false,
})
.then((res) => {
this.setState({
todos:[...todos,{username:res.data.username,todo:res.data.todo,_id:res.data._id,checked:false}]
})
console.log(todos)
})
.catch((err) => {
console.log("err", err);
});
this.setPageCount()
}
this.inpRef.current.value = ''
console.log('--------this.state.todos', this.state.todos);
}
setState is async
can you try this:
this.setState({
todos:[...todos { username:res.data.username,todo:res.data.todo,_id:res.data._id,checked:false}]
}, console.log(this.state.todos))
setState has a callback as a second arg so you can check if it's actually been set here
Related
I'm having a lot of trouble to close my Modal component once my request is done.
My method togglePop works fine with the handleClick method i have in my modal component(I did not included here).
What i m trying to do is to reverse the "Togglepop" method into the state of Modal.js. Then, setState in my axios sbmit.
Avaibaliities.js
this.state = {
showModal: false
};
}
validation = () => {
if (this.state.showDate) {
this.setState({
showModal: true
});
}
togglePop = () => {
this.setState(prevState => ({
showModal: !prevState.showModal
}));
};
render() {
{this.state.showModal && <Modal dateModal={this.state.date} toggle={this.togglePop} />} }
Modal.js
state = {
mailFilled: '',
sent: false,
showPopup: false,
closeModal: !this.props.toggle
};
handleSubmit = (event) => {
let data = {
mailFilled: this.state.mailFilled,
dateIn: dateFirst,
dateOut: dateSecond
};
axios
{
this.setState(
{
sent: true,
showPopup: true
}
)
setTimeout(() => {
this.setState({
showPopup: false
})
}, 3000);
this.setState({
showPopup: false,
closeModal: this.props.toggle
})
This is kinda new for me. I really want to understand what im a doing wrong.
Thanks in advance
Since it's a function, I think it needs to be invoked and not just referenced
this.setState({
showPopup: false,
closeModal: this.props.toggle()
});
I'm still beginner with ReactJs. Actually I want to rewrite my class components to hook components but I have a problem with one part of my code. Anyone can help me with rewrite this component to hook?
This is my code:
class App extends Component {
state = {
selected: {},
data: data,
filtered: data
};
handleChange = data => {
if (data == null) {
this.setState({
filtered: this.state.data
});
} else {
this.setState({
selected: data,
filtered: this.state.data.filter(d => d.client_id === data.id)
});
}
};
returnClientNameFromID = id => options.find(o => o.id === id).name;
render() {
const {
state: { selected, data, filtered },
handleChange
} = this;
return ( <div>
...
Here's what you could do. With useState you always have to merge objects yourself setState((prevState) => {...prevState, ... })
const App = () => {
const [state, setState] = useState({
selected: {},
data: data,
filtered: data
})
const handleChange = data => {
if (data == null) {
setState((prevState) => {
...prevState,
filtered: this.state.data
});
} else {
setState((prevState) => {
...prevState,
selected: data,
filtered: prevState.data.filter(d => d.client_id === data.id)
});
}
};
const returnClientNameFromID = id => options.find(o => o.id === id).name;
const { selected, data, filtered } = state
return() (
<div> ... </div>
)
}
I have a list of objects ("Albums" in my case) fetched from the database. I need to edit these objects.
In the editing component in the useEffect hook I fire up the action for getting the needed album using it's ID. This action works. However in the same useEffect I am trying to fetch the changed by before fired action redux state. And now I face the problem - all I am fetching is the previos state.
How can I implement in the useEffect fetching of current redux state?
I've seen similar questions here, however none of the answers were helpfull for my use case.
I am using redux-thunk.
Editing component. The problem appears in setFormData - it's fetching previous state from the reducer, not the current one. It seems that it fires before the state gets changed by the getAlbumById:
//imports
const EditAlbum = ({
album: { album, loading},
createAlbum,
getAlbumById,
history,
match
}) => {
const [formData, setFormData] = useState({
albumID: null,
albumName: ''
});
useEffect(() => {
getAlbumById(match.params.id);
setFormData({
albumID: loading || !album.albumID ? '' : album.albumID,
albumName: loading || !album.albumName ? '' : album.albumName
});
}, [getAlbumById, loading]);
const { albumName, albumID } = formData;
const onChange = e =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = e => {
e.preventDefault();
createAlbum(formData, history, true);
};
return ( //code );
};
EditAlbum.propTypes = {
createAlbum: PropTypes.func.isRequired,
getAlbumById: PropTypes.func.isRequired,
album: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
album: state.album
});
export default connect(
mapStateToProps,
{ createAlbum, getAlbumById }
)(withRouter(EditAlbum));
Action:
export const getAlbumById = albumID => async dispatch => {
try {
const res = await axios.get(`/api/album/${albumID}`);
dispatch({
type: GET_ALBUM,
payload: res.data
});
} catch (err) {
dispatch({
type: ALBUMS_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
reducer
const initialState = {
album: null,
albums: [],
loading: true,
error: {}
};
const album = (state = initialState, action) => {
const { type, payload } = action;
switch (type) {
case GET_ALBUM:
return {
...state,
album: payload,
loading: false
};
case ALBUMS_ERROR:
return {
...state,
error: payload,
loading: false
};
default:
return state;
}
};
Will be grateful for any help/ideas
You should split up your effects in 2, one to load album when album id changes from route:
const [formData, setFormData] = useState({
albumID: match.params.id,
albumName: '',
});
const { albumName, albumID } = formData;
// Only get album by id when id changed
useEffect(() => {
getAlbumById(albumID);
}, [albumID, getAlbumById]);
And one when data has arrived to set the formData state:
// Custom hook to check if component is mounted
// This needs to be imported in your component
// https://github.com/jmlweb/isMounted
const useIsMounted = () => {
const isMounted = useRef(false);
useEffect(() => {
isMounted.current = true;
return () => (isMounted.current = false);
}, []);
return isMounted;
};
// In your component check if it's mounted
// ...because you cannot set state on unmounted component
const isMounted = useIsMounted();
useEffect(() => {
// Only if loading is false and still mounted
if (loading === false && isMounted.current) {
const { albumID, albumName } = album;
setFormData({
albumID,
albumName,
});
}
}, [album, isMounted, loading]);
Your action should set loading to true when it starts getting an album:
export const getAlbumById = albumID => async dispatch => {
try {
// Here you should dispatch an action that would
// set loading to true
// dispatch({type:'LOAD_ALBUM'})
const res = await axios.get(`/api/album/${albumID}`);
dispatch({
type: GET_ALBUM,
payload: res.data
});
} catch (err) {
dispatch({
type: ALBUMS_ERROR,
payload: { msg: err.response.statusText, status: err.response.status }
});
}
};
Update detecting why useEffect is called when it should not:
Could you update the question with the output of this?
//only get album by id when id changed
useEffect(() => {
console.log('In the get data effect');
getAlbumById(albumID);
return () => {
console.log('Clean up get data effect');
if (albumID !== pref.current.albumID) {
console.log(
'XXXX album ID changed:',
pref.current.albumID,
albumID
);
}
if (getAlbumById !== pref.current.getAlbumById) {
console.log(
'XXX getAlbumById changed',
pref.current.getAlbumById,
getAlbumById
);
}
};
}, [albumID, getAlbumById]);
When using React's Class Fields syntax, how can I use async/await and try/catch on arrow functions for my "events" (markComplete, addTodo)?
Would it better to just use a constructor and bind the custom methods in there than using class fields and arrow functions?
class App extends Component {
state = {
todos: [],
};
// async/await here, I understand
async componentDidMount() {
try {
const res = await axios.get(
'http://jsonplaceholder.typicode.com/todos?_limit=10'
);
const data = await res.data;
this.setState({
todos: data,
});
} catch (err) {
console.error(err);
}
}
// Q: how can I use async/await and try/catch here?
markComplete = id => {
this.setState({
todos: this.state.todos.map(todo => {
if (todo.id === id) {
todo.completed = !todo.completed;
}
return todo;
}),
});
};
// Q: how can I use async await and try/catch here?
addTodo = title => {
axios
.post('http://jsonplaceholder.typicode.com/todos', {
title,
completed: false,
})
.then(res =>
this.setState({
todos: [...this.state.todos, res.data],
})
);
};
render() {
return (
<Router>...</Router>
);
}
}
export default App;
You can make the arrow function async as well.
addTodo = async title => {
try {
await axios.post('http://jsonplaceholder.typicode.com/todos', { title, completed: false, })
.then(res => this.setState({ todos: [...this.state.todos, res.data] }));
} catch(err) {
// Handle err
}
};
What you have with the returned promise from axios is fine, you can add a catch block to the promise chain.
addTodo = async title => {
await axios.post(
'http://jsonplaceholder.typicode.com/todos',
{ title, completed: false, }
)
.then(res => this.setState({ todos: [...this.state.todos, res.data] }))
.catch(err => {
// Handle err
});
};
I've read the docs here but I am having trouble getting the component to rerender after state is updated. The posts are being added, I just have to rerender the component manually to get them to show up, what am I missing?
I have this in the component:
class ListPosts extends Component {
state = {
open: false,
body: '',
id: ''
}
openPostModal = () => this.setState(() => ({
open: true,
}))
closePostModal = () => this.setState(() => ({
open: false,
}))
componentWillMount() {
const selectedCategory = this.props.selectedCategory;
this.props.fetchPosts(selectedCategory);
}
handleChange = (e, value) => {
e.preventDefault();
// console.log('handlechange!', e.target.value)
this.setState({ body: e.target.value });
};
submit = (e) => {
// e.preventDefault();
console.log(this.state.body)
const body = this.state.body;
const id = getUUID()
const category = this.props.selectedCategory;
const post = {
id,
body,
category
}
this.props.dispatch(addPost(post))
this.closePostModal()
}
Then down below I am adding the dispatch to props...
const mapStateToProps = state => ({
posts: state.postsReducer.posts,
loading: state.postsReducer.loading,
error: state.postsReducer.error,
selectedCategory: state.categoriesReducer.selectedCategory,
// selectedPost: state.postsReducer.selectedPost,
});
function mapDispatchToProps (dispatch) {
return {
fetchPosts: (selectedCategory) => dispatch(fetchPosts(selectedCategory)),
addPost: (postObj) => dispatch(addPost(postObj)),
}
}
export default withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(ListPosts))
Here is the code for the reducer:
case C.ADD_POST :
const hasPost = state.some(post => post.id === action.payload.postObj.id)
console.log('caseADD_POST:', action.payload.postObj.id)
return (hasPost) ?
state :
[
...state,
post(null, action)
];