I am building out a switch which reads it's checked value from the value I retrieve from the backend, and when a user toggles it, a PUT request is sent to backend to update the choice.
This is what I have so far, the toggle isn't displaying the response, what am I missing here
class Test extends Component {
constructor(props) {
super(props);
this.state = {
toggleValue: ''
}
}
componentDidMount() {
this.props.getToggleValue();
}
toggleValue = () => {
if(this.props.value){
return this.props.value.toggleValue
}
}
handleChange(field) {
return (event) => {
this.setState({
[field]: event.target.value,
});
}
}
render() {
return (
<>
<Switch value={this.state.toggleValue} checked={this.toggleValue()} onChange={this.handleChange('toggleValue')} />
</>
)
}
const mapStateToProps = (state, ownProps) => {
return {
...ownProps,
value: state.testReducer.value
};
}
const mapDispatchToProps = (dispatch) => {
return bindActionCreators({
getToggleValue
}, dispatch);
};
You have to check for event.target.checked and not event.target.value
handleChange(field) {
return (event) => {
this.setState({
[field]: event.target.checked,
});
}
}
Related
I want to repopulate the editor's state with the values i have saved to Firebase.
OnSubmit:
sendNotes = (e) => {
e.preventDefault();
let contentState = this.state.editorState.getCurrentContent()
let note = { content: convertToRaw(contentState) }
note["content"] = JSON.stringify(note.content);
this.props.createNote(note.content);
};
NoteAction:
export function getNote() {
return (dispatch) => {
database.on("value", (snapshot) => {
dispatch({
type: LOAD_NOTE,
payload: snapshot.val(),
});
});
};
}
noteReducer:
export default function (state = {}, action) {
switch (action.type) {
case LOAD_NOTE:
return action.payload;
default:
return state;
}
}
REDUX/firebase:
{
type: 'LOAD_NOTE',
payload: {
'-MNOwBIWNqY_ZFDO4ILs': '{"blocks":[{"key":"c27el","text":"ASD!!!!!!!!!!!!","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyHLvaORxEmuuJmzJ': '{"blocks":[{"key":"c27el","text":"HELLO WORLD","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}',
'-MNOyP50oGHRLiP3T5_h': '{"blocks":[{"key":"c27el","text":"This is a REDUX STORE","type":"unstyled","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}'
}
}
MapStateToProps:
function mapStateToProps(state, ownProps) {
return {
note: state.notes,
};
}
export default connect(mapStateToProps, { getNote })(TextEditor);
My Code:
componentDidMount() {
this.props.getNote();
}
componentWillReceiveProps = (nextProps) => {
if (nextProps.note !== null) {
let item = "";
_.map(nextProps.note, (note, key) => {
return (item = note);
});
this.setState({
editorState: EditorState.createWithContent(convertFromRaw(JSON.parse(item))),
});
}
};
The code is working but I'm not 100% sure about these lifecycle methods & if the code i have written is 'stable'. I am stuck with this, please :).
So I have a Context of the following format:
class UserProvider extends Component {
constructor(props) {
super(props)
this.initialize = (details) => {
this.setState(state => {
//Setting each item individually here
//e.g state.a = details.a
})
}
this.editA = () => {
this.setState(state => {
//change A here
})
}
this.editB = () => {
this.setState(state => {
//Change B here
})
}
this.state = {
a: null,
b: null,
editA: this.editA,
editB: this.editB
}
}
render() {
return (
<User.Provider value={this.state}>
{this.props.children}
</User.Provider>
)
}
}
So for each state, I have a separate function to update it. If I want to update only a single state, what should I do?
Consider implementing a generic function so that you can control your key and the corresponding value.
i.e.
const changeField = (key, value) => this.setState({ [key]: value});
Function call
changeField('a','value_a')
changeField('b','value_b')
I have a toggle switch that goes from true to false.
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}))
}
Everything is working like it is supposed to, but I want to log both the prevState and original state at the same time. I tried below adding a callback function after setting the prevState, but then it breaks my toggle switch.
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}, () => console.log(prevState)))
}
Thats not correct what you're trying to do at here
flipSwitch = () => {
console.log(this.state)
this.setState(prevState => ({
isToggleOn: !prevState.isToggleOn
}, () => console.log(prevState)))
}
You won't have access to prevState in 2nd parameter of setState.
You should modify your setState function like this
flipSwitch = () => {
console.log(this.state) // this refers to previous state here
this.setState(prevState => {
console.log(prevState) // prevState refers to previous state
return ({
isToggleOn: !prevState.isToggleOn
})
}, () => console.log(this.state) // here this refers to updated state)
}
E.g you can try
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
isToggleOn: false
};
}
flipSwitch = () => {
console.log(this.state);
this.setState(
prevState => {
console.log("prevState", prevState);
return {
isToggleOn: !prevState.isToggleOn
};
},
() => {
console.log("setState Callback", this.state);
}
);
};
render() {
return (
<div className="App">
<button onClick={this.flipSwitch}>
{this.state.isToggleOn ? "Flipped" : "Flip Switch!"}
</button>
</div>
);
}
}
export default App;
Need display data after AJAX call will be done.
My Reducer:
import { INCOME_PROFILE } from '../actionTypes'
import Immutable from 'immutable'
const initialUserState = [];
const profileReducer = function(state = initialUserState, action) {
//console.log('actiondata in reducer:' + action.data + action.type);
switch(action.type) {
case 'INCOME_PROFILE_IS_LOADING':
return Object.assign({}, state, { hh: action.hasFetched });
case 'INCOME_PROFILE':
return Object.assign({}, state, { course_list: action.data, hh: action.hasFetched });
default:
return state;
}
}
export default profileReducer
My action creator:
export function GET_ITEM_REQUEST() {
return {
type: INCOME_PROFILE_IS_LOADING,
hasFetched: false,
}
}
function receiveData(json) {
return{
type: INCOME_PROFILE,
data: json,
hasFetched: true
}
};
export function IncomeProfileList () {
return dispatch => {
return (
axios.post(Api.getURI("profile"),{}, {
headers: { 'X-Authenticated-Userid': '15000500000#1' }
}).then(function (response) {
//console.log(response.data);
dispatch(receiveData(response.data.body));
})
.catch((error) => {
console.log(error);
})
)
}
}
My component:
class IncomeProfile extends Component {
constructor(props) {
super(props)
}
componentDidMount() {
this.props.IncomeListProfile();
}
render() {
console.log(this.props.isloading);
if (this.props.isloading) {
return <p>Sorry! There was an error loading the items</p>;
}
}
}
const mapDispatchToProps = function(dispatch) {
return {
IncomeListProfile: () => dispatch(IncomeProfileList())
}
}
const mapStateToProps = function(state) {
//var mystore = state.toJS()
var mystore = state.getIn(['incomeProfileList'])['course_list'];
var mystored = state.getIn(['incomeProfileList']);
console.log(mystored.hh);
var copy = Object.assign({}, mystore);
return {
items: copy.course_list,
isloading: mystored.hh
};
}
I need next: While response not finish, I no need to display data. Condition if not works now
console.log at first time get undefined - think must be false, but it not state false. and second time it's getting true.
You don't need property 'isLoading' - just handle 2 cases in which you have your data and you haven't. Put this condition in render() function, because the component is going to refresh after passing data through the reducer. Syntax will be something like this in your case:
render() {
if(!this.props.items) {
return <div>Loading...</div>;
} else {
return (
<div>Display your data!</div>
);
}
}
Whenever my 'COLLEGE_ADDED' action is dispatched I can see the state changes in the reducer. However the update related lifecycle methods on the CollegeSearchList component and it's children aren't being called. These components aren't re-rendering presumably because of this.
I have read the docs about not mutating state and I don't think I am. Complete code can be found here https://github.com/tlatkinson/react-search-widget.
components/search/college/CollegeSearchList.js
class CollegeSearchList extends Component {
componentWillUpdate (nextProps, nextState) {
console.log(nextProps.searchItems);
console.log(nextState);
return true;
}
render () {
return (
<SearchList searchItems={this.props.searchItems} SearchListItem={CollegeSearchListItem} />
)
}
}
const mapStateToProps = (state, {id}) => {
return {
searchItems: getSearchResultsById(state.searchState, id),
SearchListItem: CollegeSearchListItem,
}
};
CollegeSearchList = connect(
mapStateToProps
)(CollegeSearchList);
reducers/search.js
const searchReducer = (searchState = [], action) => {
switch(action.type) {
case 'COLLEGE_SEARCH':
return mergeData(searchState, action, 'college', 'phrase');
case 'COLLEGE_SEARCH_SUCCESS':
return mergeData(searchState, action, 'college', 'searchResults');
case 'COLLEGE_ADDED':
return updateCollegeAdded(searchState, action.collegeId, true);
case 'COLLEGE_REMOVED':
return updateCollegeAdded(searchState, action.collegeId, false);
default:
return searchState;
}
};
export default searchReducer
const updateCollegeAdded = (searchState, collegeId, added) => {
const newState = {...searchState};
for (let id of Object.keys(newState)) {
const searchComponent = searchState[id];
if(searchComponent.searchType === 'college') {
searchComponent.searchResults.forEach(searchResult => {
if(searchResult.id === collegeId) {
searchResult.added = added;
}
});
}
}
return newState;
};
const mergeData = (data, action, searchType, propertyModified) => {
return {
...data,
[action.id]: {
searchType,
...data[action.id],
[propertyModified]: action[propertyModified],
}
};
};
actions/index.js
export const addRemoveCollege = (collegeId, collegeName, addToList) => (dispatch) => {
if (addToList) {
api.addToCollegeList(collegeId)
.then(() => {
dispatch({
type: 'COLLEGE_ADDED',
collegeId,
collegeName,
});
})
} else {
api.removeFromCollegeList(collegeId)
.then(() => {
dispatch({
type: 'COLLEGE_REMOVED',
collegeId,
collegeName,
});
})
}
};