This is my code However, after entering a value as an input and passing the value to a button, this error occurred.
Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
However, I deleted the changing state and it worked.
I couldn't figure out where or what I had missed. help me
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow strict-local
*/
import { Alert } from 'react-native';
import {
SafeAreaView,
ScrollView,
StatusBar,
StyleSheet,
TextInput,
Button,
useColorScheme,
View,
} from 'react-native';
import {
Colors,
} from 'react-native/Libraries/NewAppScreen';
import { RecoilRoot, useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil';
import { selectStatus, selectToDo, toDos } from './store/toDo';
import { useState } from 'react';
const Apps = () => {
const toDoAtom = useRecoilValue(toDos);
const setToDoAtom = useSetRecoilState(toDos)
const [nowStatus, setStatus]= useRecoilState(selectStatus)
const [toDo, onChangeToDo] = useState('')
const [selectToDos, setNewToDos] = useRecoilState(selectToDo);
const [id, setId] = useState(1)
const isDarkMode = useColorScheme() === 'dark';
const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter,
};
const onSetData = () => {
const newToDoList = [
...toDoAtom,
{
id:id,
contents:toDo,
status: "DOING"
}
]
setToDoAtom(newToDoList)
setId((id)=>id+1)
onChangeToDo("")
Alert.alert('submit')
}
const onChangeStatue = (data) => {
const targetIndex = data.id
var lists = [
...toDoAtom.slice(0, targetIndex),
{id:data.id, contents:data.contents, status:"DONE"},
...toDoAtom.slice(targetIndex + 1)
]
setToDoAtom(lists)
}
const onRest = () => {
console.log(toDoAtom)
setNewToDos([])
setId(1)
}
const onStatus = () => {
if(nowStatus == "DOING"){
setStatus("DONE")
}else if(nowStatus == "DONE"){
setStatus("DOING")
}
}
return (
<RecoilRoot>
<SafeAreaView style={backgroundStyle}>
<StatusBar barStyle={isDarkMode ? 'light-content' : 'dark-content'} />
<ScrollView
contentInsetAdjustmentBehavior="automatic"
style={backgroundStyle}>
<View
style={{
backgroundColor: isDarkMode ? Colors.black : Colors.white,
}}>
<View>
<TextInput
style={styles.input}
onChangeText={onChangeToDo}
value={toDo}
/>
<Button title='submit' color="blue" onPress={onSetData} ></Button>
<Button
title = "Reset"
color = "red"
onPress={onRest}
/>
</View>
<Button title={nowStatus} onPress={onStatus}/>
{selectToDos?.map((hi)=>(
<View key={hi.id}>
<Button title={hi.contents} onPress={onChangeStatue(hi)} ></Button>
</View>
))}
</View>
</ScrollView>
</SafeAreaView>
</RecoilRoot>
);
};
export const App = () => {
return(
<RecoilRoot>
<Apps/>
</RecoilRoot>
)
}
const styles = StyleSheet.create({
input: {
height: 40,
margin: 12,
borderWidth: 1,
padding: 10,
},
});
export default App;
import { selector, atom } from 'recoil'
export const status = atom({
key:'status',
default:'DOING'
})
export const toDos = atom({
key:'toDos',
default:[]
})
export const selectToDo = selector({
key:'selectToDo',
get: ({ get }) => {
const originalToDos = get(toDos);
const nowStatus = get(status)
return originalToDos.filter((toDo) => toDo.status === nowStatus);
},
})
export const selectStatus = selector({
key:'selectStatus',
get : ({get}) => {
return get(status)
},
set: ({set}, selectStatus) => {
set(status, selectStatus)
}
})
After selecting the status with fliter and showing the value, I tried to change the Doing status to Done.
You have a functional component that renders on every state or prop change. Each time it renders, the button's onPress method is calling the state change function when it renders.
<View key={hi.id}>
<Button title={hi.contents} onPress={onChangeStatue(hi)} ></Button>
</View>
onPress should receive a callable function, not an invoked function:
<View key={hi.id}>
<Button title={hi.contents} onPress={() => onChangeStatue(hi)} ></Button>
</View>