I'm trying to create variables and a function inside a state like this
state = {
modalVisible: false,
photo:""
getDataSourceState
}
which i have done, how can i call the function outside the state and set a new state.
This what i have done but i keep getting errors
getDataSourceState() {
return {
dataSource: this.ds.cloneWithRows(this.images),
};
}
this.setState(this.getDataSourceState());
see what prompted me to ask the question, because i was finding it difficult to access modalVisible in the state since there is a this.state = this.getDataSource()
constructor(props) {
super(props);
this.state = {
modalVisible: false,
photo:"",
sourceState: getDataSourceState()
}
this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.lastPhotoFetched = undefined;
this.images = [];
this.fetchPhotos();
this.getDataSourceState = this.getDataSourceState.bind(this)
}
componentDidMount(){
this.getDataSourceState();
}
getDataSourceState() {
return {
dataSource: this.ds.cloneWithRows(this.images),
};
}
getPhotosFromCameraRollData(data) {
return data.edges.map((asset) => {
return asset.node.image;
});
}
}
You can't the way you have attempted but technically yes, you can have a function that returns the desired state you want initialised in your constructor. I wouldn't suggest doing it though.
You will quickly run into issues where your components aren't updating state correctly.
What you are looking for is a function that returns a value as opposed to sets state. You would do something like this:
constructor(){
super()
this.state = {
modalVisible: false,
photo:""
sourceState: this.getDataSourceState()
}
this.getDataSourceState = this.getDataSourceState.bind(this)
}
getDataSourceState(){
return this.ds.cloneWithRows(this.images)
}
As I mentioned, it is not a good idea to do it this way. You are better off initialising the state values as a default value and then setting the state in your componentDidMount like so:
constructor(){
super()
this.state = {
modalVisible: false,
photo:""
sourceState: null
}
this.getDataSourceState = this.getDataSourceState.bind(this)
}
componentDidMount(){
this.getDataSourceState()
}
getDataSourceState(){
const data = this.ds.cloneWithRows(this.images)
this.setState({soureState: data})
}
This way you have a reusable function which you can call in componentDidUpdate() if need be for when you move navigate between the same component with different data and want the state to update.
Yes you can.
class App extends Component {
func1 = () => {
this.setState({flag:!this.state.flag})
}
state = {
flag:true,
doclick:this.func1
}
}
Related
I have a react class based component where I have defined a state as follows:
class MyReactClass extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedDataPoints: new Set()
};
}
// This method is called dynamically when there is new addition of data
storeData = (metricName, dataPoint) => {
if (this.state.selectedDataPoints.has(dataPoint)) {
this.state.selectedDataPoints.delete(dataPoint);
} else {
this.state.selectedDataPoints.add(dataPoint);
}
};
render () {
return (
<p>{this.state.selectedDataPoints}</p>
);
}
}
Note that initially, the state is an empty set, nothing is displayed.
But when the state gets populated eventually, I am facing trouble in spinning up the variable again. It is always taking as the original state which is an empty set.
If you want the component to re-render, you have to call this.setState () - function.
You can use componentshouldUpdate method to let your state reflect and should set the state using this.state({}) method.
Use this code to set state for a set:
export default class Checklist extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedDataPoints: new Set()
}
this.addItem = this.addItem.bind(this);
this.removeItem = this.removeItem.bind(this);
}
addItem(item) {
this.setState(({ selectedDataPoints }) => ({
selectedDataPoints: new Set(selectedDataPoints).add(item)
}));
}
removeItem(item) {
this.setState(({ selectedDataPoints }) => {
const newSelectedDataPoints = new Set(selectedDataPoints);
newSelectedDataPoints.delete(item);
return {
selectedDataPoints: newSelectedDataPoints
};
});
}
getItemCheckedStatus(item) {
return this.state.checkedItems.has(item);
}
// This method is called dynamically when there is new addition of data
storeData = (metricName, dataPoint) => {
if (this.state.selectedDataPoints.has(dataPoint)) {
this.state.selectedDataPoints.removeItem(dataPoint);
} else {
this.state.selectedDataPoints.addItem(dataPoint);
}
};
render () {
return (
<p>{this.state.selectedDataPoints}</p>
);
}
}
I'm returning an empty div until my socket connection is done, and i got the data from it.
But setState never forces a re-render, why and how do I fix it?
Check LoadData() and Render()
class LoadNames extends React.Component{
constructor(props)
{
super(props);
this.state = {names: []}
this.loaded = false;
this.loadData = this.loadData.bind(this);
}
componentDidMount()
{
this.loadData();
}
loadData()
{
socket.on("updateCatagories", (data) => {
//entry point
console.log("UPDATE RECIEVED, NEW DATA: ");
this.loaded = true;
this.setState((state, props) =>
{
this.names = data
})
console.log(this.names);
});
}
render()
{
console.log(this.loaded);
if (this.loaded === false)
{
return <div />
}
return <h1>here: {this.state.names[3].name}</h1>
}
}```
You are not updating the state correctly.
You need to return the object literal from the callback function passed to this.setState(...)
this.setState((state, props) => ({ names: data }));
In your case, since new state is independent of the previous value of the state, you could update the state as shown below:
this.setState({ names: data });
Side note: You are logging this.names (it should be this.state.names) immediately after calling this.setState() but state is updated asynchronously, so it won't log the new value of this.state.names.
To log the updated value of state, you could pass second argument to this.setState() that is a callback function which is called after the state has been updated.
this.setState({ names: data }, () => {
console.log(this.state.names)
});
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).
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
}));
}
});
}
I want to create a component that hides itself after a few seconds. I have 2 questions:
Where should I place the setTimeout? Probably in the constructor, componentWillMount, or componentDidMount. Is there a differences in placing it in componentWillMount or componentDidMount?
Is it bad practice to do this.state = ... outside the constructor?
Here's what I have:
class Message extends React.Component {
constructor() {
super();
this.state = {
closed: false,
closeTimeout: null
};
}
componentDidMount() {
if (this.props.closeAfter) {
this.state.closeTimeout = setTimeout(_ => {
this.setState({closed: true});
}, this.props.closeAfter);
}
}
componentWillUnmount() {
if (this.state.closeTimeout) {
clearTimeout(this.state.closeTimeout);
}
}
render() {
return ...
}
};