Rerender Flatlist after Call api then setState - javascript

I just started learning React native, and want to render FlaList after setState.
I am try to call Api to get Data and then I sorting that data but the FlatList is not rerender with newData. I also try extraData but nothing happen. Where am I missing?
Thank for your help.
function HomeScreen(props) {
const {transactions = []} = useSelector(selectors.transactions) || [];
const [listTransaction, setListTransaction] = useState([]);
useEffect(() => {
dispatch(BalanceActions.balanceRequest()); // This is my call Api
sortListTransaction(); // I call sortFunc after that
}, []);
const sortListTransaction = () => { // In this function I group by date the array of the result Api
let groups = [];
transaction.forEach((item) => {
let date = moment(item.date).format('MM/DD/YYYY');
if (date in groups) {
groups[date].push(item);
} else {
groups[date] = new Array(item);
}
});
setListTransaction(groups);
};
const _renderItem = ({item}) => {
return <BodyContent data={item} />;
};
// Then my FlatList like:
return (
<FlatList
data={listTransaction}
keyExtractor={(item) => item.id}
renderItem={_renderItem}
extraData={listTransaction}
/>
)
}

Related

Empty Object on React useEffect

In my project I have the component ExportSearchResultCSV. Inside this component the nested component CSVLink exports a CSV File.
const ExportSearchResultCSV = ({ ...props }) => {
const { results, filters, parseResults, justify = 'justify-end', fileName = "schede_sicurezza" } = props;
const [newResults, setNewResults] = useState();
const [newFilters, setNewFilters] = useState();
const [data, setData] = useState([]);
const [isLoading, setIsLoading] = useState(true)
const [headers, setHeaders] = useState([])
const prepareResults = () => {
let newResults = [];
if (results.length > 1) {
results.map(item => {
newResults.push(parseResults(item));
}); return newResults;
}
}
const createData = () => {
let final = [];
newResults && newResults?.map((result, index) => {
let _item = {};
newFilters.forEach(filter => {
_item[filter.filter] = result[filter.filter];
});
final.push(_item);
});
return final;
}
console.log(createData())
const createHeaders = () => {
let headers = [];
newFilters && newFilters.forEach(item => {
headers.push({ label: item.header, key: item.filter })
});
return headers;
}
React.useEffect(() => {
setNewFilters(filters);
setNewResults(prepareResults());
setData(createData());
setHeaders(createHeaders());
}, [results, filters])
return (
<div className={`flex ${justify} h-10`} title={"Esporta come CSV"}>
{results.length > 0 &&
<CSVLink data={createData()}
headers={headers}
filename={fileName}
separator={";"}
onClick={async () => {
await setNewFilters(filters);
await setNewResults(prepareResults());
await setData(createData());
await setHeaders(createHeaders());
}}>
<RoundButton icon={<FaFileCsv size={23} />} onClick={() => { }} />
</CSVLink>}
</div >
)
}
export default ExportSearchResultCSV;
The problem I am facing is the CSV file which is empty. When I log createData() function the result is initially and empty object and then it gets filled with the data. The CSV is properly exported when I edit this component and the page is refreshed. I tried passing createData() instead of data to the onClick event but it didn't fix the problem. Why is createData() returning an empty object first? What am I missing?
You call console.log(createData()) in your functional component upon the very first render. And I assume, upon the very first render, newFilters is not containing anything yet, because you initialize it like so const [newFilters, setNewFilters] = useState();.
That is why your first result of createData() is an empty object(?). When you execute the onClick(), you also call await setNewFilters(filters); which fills newFilters and createData() can work with something.
You might be missunderstanding useEffect(). Passing something to React.useEffect() like you do
React.useEffect(() => {
setNewFilters(filters);
setNewResults(prepareResults());
setData(createData());
setHeaders(createHeaders());
}, [results, filters]) <-- look here
means that useEffect() is only called, when results or filters change. Thus, it gets no executed upon initial render.

How to create an image grid with React Native after collecting data from Axios?

I am trying to create an image grid like the following on React Native.
I have managed to extract the data from https://pokeapi.co/ using Axios. My code is as the following so far but doesnt seem to work. The code below retrieves data from the API and I have set that data to setPokemon (How to I access this data) I have tried to assign that data to {data} below to be used inside the flatlist but its not working. It doesnt seem to assign the data at all.
export default function App() {
const [pokemons, setPokemon] = useState([])
//Fetching Pokemon from online database
async function fetchPokemon() {
try {
const { data } = await axios.get('https://pokeapi.co/api/v2/pokemon?limit=50')
setPokemon(data.results) // ASSIGN DATA TO setPokemon
}
}
//Hook to fetch Pokemon upon component mount
useEffect(() => {
fetchPokemon()
}, [])
const renderPokemon = (item, index) => {
return <Text>{item.name}</Text>
}
const {data} = setPokemon // ALL POKEMON SHOULD BE INSIDE THIS
return (
<SafeAreaView>
<FlatList
style={styles.container}
data={data} // ALL POKEMON SHOULD BE INSIDE THIS
renderItem={renderPokemon}
keyExtractor={pokemons => `key-${pokemons.name}`}
>
</FlatList>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1
},
});
Any tips on this?
You are trying to access data from the state setter function. After calling setPokemon(5), pokemons will be 5.
const {data} = pokemons expects your data to be an object, but you've initialized it as a list, and it looks like you're trying to populate it as a list. Do you mean to write const data = pokemons to simply rename it rather than destructuring it?
Assuming that data.results is a list of stuff, here's what the working component will look like:
function App() {
const [pokemons, setPokemon] = useState([]);
async function fetchPokemon() {
try {
const { data } = await axios.get('https://pokeapi.co/api/v2/pokemon?limit=50')
setPokemon(data.results)
}
}
useEffect(fetchPokemon, [])
const renderPokemon = (item, index) => {
return <Text>{item.name}</Text>
};
return (
<SafeAreaView>
<FlatList
style={styles.container}
data={pokemons} // ALL POKEMON SHOULD BE INSIDE THIS
renderItem={renderPokemon}
keyExtractor={pokemons => `key-${pokemons.name}`}
>
</FlatList>
</SafeAreaView>
);
};
Edit: it seems like there is another error related to object destructuring. If you look at the FlatList docs the renderItem requires a function with this signature: (o: {item: T, index: number}) => Element. Simply update your renderPokemon function.

Deep copy data update problem in react native

I am using this
const HomeProfile = ({data}) =>{
var tempData = {}
const onOptionClick = ( clicked_index) => {
tempData = { ...data[0].atpData }
tempData.selected_index = clicked_index
}
const addInProps = () =>{
data[0].atpData=tempData
}
const checkData = () =>{
console.log('tempData',tempData)
}
return(
<View>
<Text></Text>
</View>
)
}
When check data in checkData function it is giving me the empty data. But if i am using this hooks like
const [tempData,settempData] = usestate({})
My Problem:
It is working good as i am using it with var tempData = {} but problem in that after adding data. Still getting empty Data in the checkData() functions
If i am using with const [tempData,settempData] = usestate({}) then it is changing my data in the data[0].atpData without hitting the function so i am not getting how to resolve it. But i am getting data checkData() function as i required.
You should use useState hook, so you need initialize it as empty object, and call setter inside your method as you desire:
const HomeProfile = ({data}) =>{
const [tempData, setTempData] = useState({})
const onOptionClick = ( clicked_index) => {
setTempData({...data[0].atpData, selected_index: clicked_index})
}
const addInProps = () =>{
data[0].atpData=tempData
}
const checkData = () =>{
console.log('tempData',tempData)
}
return(
<View>
<Text></Text>
</View>
)
}
you can use useEffect hook when detect the object change

Javascript Promise.all results from fetching multiple apis not rendering in the React Native FlatList

I am using Promise.all in order to fetch multiple apis.
const ListScreen = () => {
const first = fetch('https://EXAMPLEAPI').then(resp => resp.json())
const second = fetch('https://EXAMPLEAPI').then(resp => resp.json())
const third = fetch('https://EXAMPLEAPI').then(resp => resp.json())
const retrieveAll = async function () {
let results = await Promise.all([first, second, third])
When console.log(results), I get all arrays of objects from apis
The problem is that when I create a FlatList, I don't get anything to be rendered on the screen(blank)
const retrieveAll = async function () {
let results = await Promise.all([first, second, third])
return (
<FlatList
keyExtractor={item => item.title}
data={results}
renderItem={({ item }) => {
return <Text>{item.title}</Text>
}}
/>
)
};
}
export default ListScreen;
What am I doing wrong?
Please help. :(
You need to re-render the component, for that you will have to use react Hooks.
This is how the component will look like
const RetrieveAll = function () {
const [ results, setResults ] = useState([])
useEffect( () => {
Promise.all([first, second, third])
.then(response => {
setResults(response)
})
}, [])
return (
<FlatList
keyExtractor={item => item.title}
data={results}
renderItem={({ item }) => {
return <Text>{item.title}</Text>
}}
/>
)
};
Usage
<RetrieveAll />
And try not to create async JSX elements.

How to create a react native state with key and value array?

I've a flatlist with a list of options and a checkboxes in each row, and I need a state for the checkboxex, using hooks. I tought create a key-value relationship, an associative array somehow, so I can access to the proper state using the "item.option" as key:
export default function Questions({ navigation, route }) {
const [questionNumber, setQuestionNumber] = useState(0);
const data = route.params.data;
const numberOfQuestions = Object.keys(data.questions).length;
const [selectedOption, setSelectedOption] = useState([null]);
const [toggleCheckBox, setToggleCheckBox] = useState([false])
[...]
const renderItemMultipleChoice = ({ item }) => {
console.log(toggleCheckBox[item.option],item.option); //******here I get undefined
return (
<View style={[styles.option]}>
<CheckBox style={styles.checkBox}
disabled={false}
value={toggleCheckBox[item.option]}
onValueChange={(newValue) => multipleChoiceHandler(item.option, newValue)}
/>
<Text style={styles.optionText}>{item.option}</Text>
</View>
);
};
const multipleChoiceHandler = (item, newValue) => {
var newHash = toggleCheckBox
newHash[item] = newValue;
setToggleCheckBox({toggleCheckBox: newHash});
}
useEffect(() => {
if (data.questions[questionNumber].type_option != "open_choice") {
for (i = 0; i < Object.keys(data.questions[questionNumber].options).length; i++) {
var newHash = toggleCheckBox
newHash[data.questions[questionNumber].options[i].option] = false;
//*******every checkbox is false at the beginning...
setToggleCheckBox({toggleCheckBox: newHash});
console.log("toggle checkbox:",toggleCheckBox[data.questions[questionNumber].options[i].option],
data.questions[questionNumber].options[i].option); //****** here I get all false, the value I setted.
}
setSelectedOption([null]);
}
}, [questionNumber])
return(
<FlatList style={styles.flatlistOption}
data={data.questions[questionNumber].options}
renderItem={renderItemMultipleChoice}
keyExtractor={(item) => item.option}
/>
)
}
I'm supernoob about react, so to insert the intial state of toggleCheckBox for each element (using the parameter option to refer to the proper array element), I've used a for cycle... I know it's not proper and quite spaghetti code. Btw it should work, but when I try to access from the checklist to the toggleCheckBox state I get a undefined, so the checkbox state doesn't work properly. I don't know what I'm missing...

Categories

Resources