LayoutAnimation not working when reordering flatlist items - react-native

I'm trying to let my flatlist animate every time the order of my list gets changed. For this I tried using the LayoutAnimation API from react native. My state gets updated via redux. When I delete or add new items to the list it works completely fine but it doesn't when I try to change the sortOrder in all my items.
Code
When I finishing a workout. I log the workout which returns me the new reordered workoutList from my API.
LayoutAnimation.easeInEaseOut();
dispatch(logWorkout(inputWorkout));
navigation.navigate("WorkoutListScreen");
logWorkout
export const logWorkout = (workout: Workout) => async (
dispatch: Dispatch<WorkoutDispatchTypes>
) => {
console.log('WORKOUT_LOG_ACTION');
// dispatch({
// type: LOG_WORKOUT_LOADING,
// })
_logWorkout(workout)
.then((result: any) => {
handleNewTokenForRequest(result.headers.authorization, dispatch);
// LayoutAnimation.easeInEaseOut()
dispatch({
type: LOG_WORKOUT_SUCCESS,
payload: {
workoutList: result.data.filter(
(item: any) => item.archived === false
),
archivedWorkoutList: result.data.filter(
(item: any) => item.archived === true
),
message: lang.t('LOG_WORKOUT_SUCCESS'),
},
});
dispatch < any > getLogHistory();
})
.catch((err) => {
if (handleUnauthorizedRequest(err, dispatch)) return;
console.log(err.response);
console.log(err);
dispatch({
type: LOG_WORKOUT_FAIL,
payload: {
message: lang.t('LOG_WORKOUT_FAIL'),
},
});
});
};
Attempts
I got the sortOrder of every item as the itemĀ“s key.
KeyExtractor of the Flatlist is also using the sortOrder of the items.
My LayoutAnimation is executed before my state is updated.
I have also tried to use Transitions from react reanimated
Also added the following code to make it work for android
if (Platform.OS === 'android') {
if (UIManager.setLayoutAnimationEnabledExperimental) {
UIManager.setLayoutAnimationEnabledExperimental(true);
}
}
I don't really know what else to try.
Please let me know if you need some code or further information.
Does anybody have a tip for me? I really don't understand why it's not working.
Nobody got an idea? I still couldn't fix the problem.

Related

Unable to set useState variable in async method and console log it

Im working with my friends on a app project and we find an issue many times when we tring to set a use state and the console log the variable, i've looking for a solution in the website and saw that the reason is that the usestate is an async awiat which means the variable that i set in the use state isn't immidatly set in it, so i tried many solution that i found in the websites but none of them work for me.
in the screenShot you can see that the json variable is in console log before and the set varaible doesn't show after the setActiveUser , any help?
Thanks!
If you want to do something upon setting state then your best bet is to use the useEffect hook from React and adding your state in the dependency array. This will then call the function in your useEffect every time the state changes. See below a rough example:
import { Text } from 'react-native';
const MyComponent = () => {
const [activeUser, setActiveUser] = useState(null);
useEffect(() => {
// This should log every time activeUser changes
console.log({ activeUser });
}, [activeUser]);
const fetchAuthentication = async user => {
var flag = false;
await fetch('/api/authUser/', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
})
.then(res => {
res.ok && (flag = true);
return res.json();
})
.then(json => {
if (flag) {
setActiveUser(json);
}
})
.catch(error => console.error(error));
return flag;
};
return <Text>Hi</Text>;
};
Full documentation: https://reactjs.org/docs/hooks-effect.html

React Native useEffect() re-renders too much

i have a useEffect function where a redux action is called and data is written to prop. My Problem is that useEffect loop many times and flooded the server with requests.
const { loescherData, navigation } = props;
useEffect(() => {
AsyncStorage.getItem('userdata').then((userdata) => {
if (userdata) {
console.log(new Date());
console.log(userdata);
var user = JSON.parse(userdata);
props.fetchLoescherDetails(user.standort);
setData(props.loescherData);
}
});
}, [loescherData]);
if i leave it blank the rendering is finished before receiving data and the content would not updated.
is there another way to work with this function?
loescherData won't be available right after calling your redux-action fetchLoescherDetails ... and changing component by setData will cause an infinite rendering cause your current useEffect has a dependency on loescherData
So I'd suggest you exec your redux-action onComponentDidMount by passing an empty-deps [] to your effect ... and then consume the output of you action in a different effect
useEffect(() => {
AsyncStorage.getItem('userdata').then((userdata) => {
if (userdata) {
console.log(new Date());
console.log(userdata);
var user = JSON.parse(userdata);
props.fetchLoescherDetails(user.standort);
// setData(props.loescherData);
}
});
}, []);
useEffect(() => {
if (loescherData) {
// do some with loescherData like setState
}
}, [loescherData]);

React-admin - Cannot update a component (`xxx`) while rendering a different component (`SelectInput`)

React-admin 3.8.4
I'm rendering some form fields conditionally, and these fields have some validations. Because of this, I'm receiving this error below:
Warning: Cannot update a component (nameOfTheComponent) while rendering a different component
(SelectInput). To locate the bad setState() call inside SelectInput, follow the stack trace
as described in...
I already have read some explanation about the problem and I've discovered that react-final-form
calls a setState() when registering those fields and this seems to be the issue.
I also saw that there is a fix into FileConfig called silent that solves this problem React final form silent
But I don't know if I'm using wrong, because the warning remains showing up.
I'm trying to do something like this:
const OfferVariation = ({ formData, ...rest }) => {
const form = useForm();
useEffect(() => {
return () => {
const initialState = {}
let inConstructor = true
const fieldName = "internalOffer.type"
form.registerField(fieldName, fieldState => {
if (inConstructor) {
initialState[fieldName] = fieldState
} else {
this.setState({ [fieldName]: fieldState })
}
}, { silent: true })
}
}, [])
if (flowType === "Interna") {
return (
<SelectInput
source="internalOffer.type"
label="Tipo da Oferta"
choices={offerTypes}
validate={validateArrayNotEmpty}
{...rest}
/>
)
} else if (flowType === "Externa") {
return (
<TextInput
label="Url Externa"
source="externalOffer.externalURL"
{...rest}
/>
)
}
}
};
export default OfferVariation;
Does anyone know how to fix it and could help me?

a state mutation was detected inside a dispatch (NOT "in between" dispatch)

...inside a dispatch, in the path: "chat.messages.0' Take a look at the reducer(s) handling the action {'type': 'chat', 'payload': {'sender': 'you', 'body': 'foo'}}`
My reducer:
chatMessage.js:
export default (state, action) => {
return Object.assign({}, {
...state,
messages: [...state.messages, action.payload]
})
}
Interestingly, if I use messages=[] in my Chat component, I don't get this error.
export default class Chat extends React.Component {
state = {...this.props.data, input: "", toggle: false}
_renderItem = ({item}) => {
return <ChatMessageRow data={item} />
}
render() {
// var {messages} = this.state
var messages = []
return (
<View style={styles.container}>
<FlatList
inverted
renderItem={this._renderItem}
style={styles.logWrapper}
data={messages.reverse()}
extraData={this.state.toggle}
/>
from my main view, which is bound to Redux:
return (...other views... check if tabIndex == 1, show <Chat data={this.props.chat} ... />
I ran into an issue earlier with the FlatList rendering in Chat not updating and I had to do a
this.setState({messages: messages.push(newMessage), toggle: !this.state.toggle})
to update the state so the Flat List would recognize it's changed.
Now I am loading my data from a Chat store using connect and redux, then passing that data into the component.
I get the error when I try to reload the Chat component after adding chat messages. Weirdly I can get one to update but after adding one it will not show others.
At first I think this is a problem in my reducer so I rewrite the reducer to use the Object assign and array spread operator.
Now I think it is related to the rendering which is unexpected.
How do I debug this?
EDIT:
It's not "it works with adding 1 message". It's - I can bring the view out of focus and back into focus one time. So..
Open Chat Tab
Observer 1 message
Add N messages to store using redux actions
Change tabs, revert back to Chat
Observer N messages added
Add M messages
Change tabs, click back to Chat tab
Error shows
EDIT:
I tried
using ...spread, but redux still throws warning about state mutation 's suggestion doing
export default (state, action) => {
return Object.assign({}, {
...state,
messages: state.messages.map(value => Object.assign({}, value)).concat(action.payload)
})
}
in my reducer, same error.
EDIT:
My reducer is update to chatMessage.js
I think the issue is in how I'm calling this.
I am writing a websocket controller. I don't need to wait for a response when I send a message like I would with an HTTP response.
My websocket controller:
onMessage = ({data}) => {
const json = JSON.parse(data)
if (json) {
if (json.status) {
const reducer = this.stateFilters[json.status]
if (reducer) {
reducer(json.body)
} else {
console.log("No reducer")
}
}
}
}
the websocket controller is created in my View component:
my main view
import {ChatStateFilters} from '../../reducers/chat'
const mapDispatch = { chatMessage }
this.wsController = new WebSocketController({
stateFilters: {chatMessage: this.props.chatMessage},
from the chat reducer file (that contains the chatMessage reducer)
Those state filters get created when I create my slice.
The value of stateFilter['chatMessage'] -- which is the value of what gets bound to my View's prop in mapDispatchToProp
is this function:
let fn = (payload) => {
return dispatch => {
dispatch(stateFilters[actionName](payload))
}
}
exportedStateFilters[actionName] = fn
I think the problem is somewhere in here^... somehow the dispatch is firing, updating state but redux doesn't know the dispatch is finished
EDIT 2:
I thought the lack of async may have been an issue. So I changed the stateFilter (the fn that gets bound to my prop in the view) to this:
let fn = (payload) => {
return dispatch => {
post("", {}, true)
.then(response => {
dispatch(stateFilters[actionName](payload))
})
.catch(error => {
dispatch(stateFilters[actionName](payload))
})
}
}
and now it works a few more times.. then gives me the error "A state mutation was detected between dispatches".
My chat message reducer is still
export default (state, action) => {
let messages2 = Object.assign([], [...state.messages, action.payload])
return Object.assign({}, {...state, messages: messages2 })
}
so why is this error happening?

React Native Pass data to another screen

I need to pass some data from one screen to another, but I don't know how to do it. I've searched and I read about Redux, but it is a bit complicated since I never used it and most of the tutorials are confusing for a newcomer. But if I could do it without Redux, that would be better.
So, when I click in a button, It runs this:
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson)
})
}
and I want to pass the data I get from this, to another screen.
Im using router-flux, if that matters.
you can save the response in state of your current component like
onSearch() {
var listaCarros = fetch(`URL`, {
method: 'GET',
})
.then((response) => { return response.json() } )
.then((responseJson) => {
console.log(responseJson);
/*for react-native-router-flux you can simply do
Actions.secondPage({data:responseJson}); and you will get data at SecondPage in props
*/
this.setState({
dataToPass :responseJson
});
})
}
then below in return like you want to pass data to a new component having named as SecondPage, you can do it in following way
render(){
return(
{this.state.dataToPass && <SecondPage data ={this.state.dataToPass}>} //you will get data as props in your second page
);
}