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
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.
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.
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
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.
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...