I am new to redux world and I am trying to make newspaper app. I am currently working on the search functionality where the user can search for specific newspaper title. The problem is that when I first types eg 'a' the state is ''. And when I type more eg 'b' the state shows that the term is 'a' when it should be 'ab'. I am using redux chrome tools to check this global state.
My Actioncreator is really simple (only returns the term passed to it):
export function search(term) {
return{
type:SEARCH,
term
}
}
Here is the reducer:
const SearchReducer = (state = '', action) => {
switch (action.type) {
case SEARCH:
return action.term;
default:
return state;
}
}
Here is the root reducer:
/*Application state*/
const rootReducer = combineReducers({
weather: WeatherReducer,
filters: FilterReducer,
articles:ArticleReducer,
search: SearchReducer // this should be 'ab', but is 'a'
});
This is really simple setup. Here is how I am communicating with redux.
I have my material-ui textfield (i tried vanilla input field too)
<TextField style={style.searchWidget.search}
floatingLabelText="Search"
value={this.state.term}
onChange={this._onSearchChange}
/>
When the user types something the _onSearchChange func is fired.
_onSearchChange(event) {
this.setState({term: event.target.value});
this.props.search(this.state.term);
}
This will set current state for this search component. Then it will dispatch search action which will update the global state. But does not work correctly. The global state is always 1 step behind.
Any idea?
Edit:
It looks like it is not redux but react. The component state is not updating instantly. Correct term is passed to the actionreducer so it is not redux's fault. I tried to print out this.state.term after setting the state. And it looks like the state is not updating.
This answer adds a bit onto what Aniket Nandan pointed out -- you are using setState inside of your React component instead of relying on props from above.
The main purpose of using Redux is to take your state and put it in a container alongside the application. The benefit in doing so is that your state can be shared across multiple components and you can then pass things via props into the components in your component tree.
The use of a state container (which has always reminded me a bit of using state machines) allows you to build your application without the complication of having to hand callbacks down through the tree to get changes to go back up to the top. Instead, Redux handles the changes to state and hands everything back off to React through props.
_onSearchChange(event) {
this.setState({term: event.target.value});
this.props.search(this.state.term);
}
On that note, looking at the code above, from your post, I am wondering why you setState to the term, but then always call a function you received through props? Does the search then call up to the dispatch method from the Redux store? If not, then you are not quite wired up correctly.
Further to that point, if you used connect correctly (from react-redux), then you should have the dispatch method from the Redux store available (this happens through context).
The way Redux is designed to work is something more like this:
_onSearchChange(event) {
this.props.dispatch({ type: 'SEARCH', term: event.target.value });
}
What would then happen is Redux should handle the state updates, and the new state will flow from Redux to React via props (this happens through all the connections under the hood in Redux, which is pretty awesome!).
const SearchReducer = (state = '', action) => {
switch (action.type) {
case SEARCH:
return action.term;
break;
default:
return state;
}
}
Based on your reducer (copied above ^^) and your use of combineReducers, you should end up with a state that has { search: { term: 'ab' } } if you typed 'ab', and it should be 'a' after typing only 'a', rather than lagging behind.
What was actually happening with your use of setState and the method coming from props was the initial state (I'm assuming '') was being passed to this.props.search, the first time. Meanwhile, state was updating on the component to be 'a' after you typed 'a'. Then, the next time, when you typed 'b', the state was updating to 'ab', but this.props.search was only receiving the term from state before the setState finished executing -- while it was still 'a'.
This is actually one of the reasons why Redux is so awesome -- it provides a way to ensure that state is updated properly based on user actions within its own container, so that you can guarantee things are in sync across your application.
On that note, I will leave a piece of advice for working with Redux: You should rarely find yourself using setState within a React component that is in an application using Redux. The decision of when to use setState within a component should hinge on whether the piece of state you want to set only exists within that component and the rest of the application does not need to know about it. I cannot think of an example, and any I could offer would probably be quite contrived. To that point, the reason I can't think of one is because I think it is quite a rarity that you would have such a use case in an application.
So, you should be sticking to only using the dispatch method from the Redux store and allowing Redux to handle the state updates through its workflow and allow state to flow downward through props to the components. Adhering to this flow will prevent a lot of these weird "states getting out of sync" types of issues that can happen.
Actually it is not related to redux. You'll have to remember while working with react that you can not get the updated state as soon as you update your react state. let's take an example.
getInitialState: function() {
return {
myState: 0
}
},
updateState: function(stateVersion) {
console.log(this.state.myState); //this will print 0
this.setState({ myState: stateVersion });
console.log(this.state.myState); //this will print 0
}
now for the first time if we call updateState function with state version as argument it will print 0 for both the console even if we sent 1 or 2 or any number as argument.
suppose we have sent 2 as argument. then we can get that state in the next call of that function with another arguments.
But react also take care of this.
You may think that if the state is not updated as soon as we update that then how can I work with that. But react is a good boy...
if you call a function to update a state and next you call another function to work with last updated state then you can work with that.
I think I have already answered your question that why not redux state is updated.
another think is that when you are using redux state for your search reducer then why you are also handling react state. you can directly pass the searched params into your action. You can get that update instantly from your reducer state.
It will help your code simplicity.
I found the solution.
React - State not updated
It appears that the setState is actually not instantly setting the state.
So I used a callback function instead.
_onSearchChange(event) {
this.setState({term: event.target.value}, function () {
console.log(this.state.term)
});
}
Now when I type 'a' it will log 'a'!
Related
I am working on this QR code based application which is using a ClearDB MySQL database that is stored on Heroku servers. The frontend communicates with the database by using a REST API built with Node.js and Express
Whenever a user scans a QR code, the value of the code changes in the database. But I don't know how to reflect that change instantly in the frontend. Basically what I need help with is finding a way to automatically refresh the page whenever that value changes in the database and display the new QR code based on the new value. Such that when a user scans the code, it instantly updates on his page, not only in the database.
I looked into sockets but didn't quite understand how to integrate it into my application, especially when it comes to the frontend.
You can use a state value for detecting the change.
You declare a state value of which type is boolean(any type you want). Then you can implement setState function(in case of class component) or useState hook(in case of functional component) in the module of updating data in the database.
For example:
const [isChanged, setChanged] = useState(false);
const updateQRData = (data) => {
... Update codes
setChanged(isChanged => !isChanged);
}
Then you can use useEffect hook:
useEffect(() => {
... Write some codes
}, [isChanged]);
How are you storing the information for the QR codes? In Redux? Or local state? Are you using class-based components or hooks? If you want the least amount of headaches, I'd heavily suggest hooks. Let me know and I can give more specifics for the code.
Your final product would look something like this:
const [qrData, setQrData] = useState(null)
const updateDatabase = () => {
axios.post(`your/database/url/with/your/data/attached`).then(res => {
setQrData(res.data.your.response.object.from.database)
}
}
I have below folder structure with gatsby react
How can I call a rest full api when using gatsby? I have gone through this but don't know how do I call multiple api at once on different components.
This really depends on what you're trying to achieve and is a very broad question. Firstly, the file structure image above has no bearing whatsoever on the solution. Secondly, don't be hung up about Gatsby. Gatsby is a tool for building React apps, so you're really just building and populating React components, so if you're stuck, search for help using React.
It really depends if you're trying to populate a bunch of components in a page ready for the user to use or whether you need to 'control state' for a page containing lots of components that share data. You can call an API from the component itself, or you can call the API from a 'parent' component and pass the data into the target (known as Child) component.
If I have a component that needs data but the data isn't used for app state, then I'd use the componentDidMount() method of the component itself, which is clearly demonstrated in the link you posted. For example, you want a dropdown/select loaded with a set of default data.
componentDidMount(){
fetch(ApiURL)
.then(result=>result.json())
.then(result=>this.setState({countries}, this.buildSelectOptions(countries)))
}
What this does is when the component has been mounted on the page, the componentDidMount method fires. This then calls the fetch command and sticks the raw results into the countries state property. It then calls the 'this.buildSeletOptions(countries)' method to build the 'options' array for the select component.
E.g.
buildSelectOptions(countries){
var optionsArray[];
var newCountry={key: 1, value:'All', text:'All'};
optionsArray.push(newCountry);
for(var i = 0; i < countries.length; i++) {
let nextCountry = {key: i+2, value:countries[i].name, text:countries[i].name};
optionsArray.push(nextCountry);
}
this.setState({options: optionsArray});
}
To call multiple APIs at once, I would go to the first parent where all affected child components are underneath. E.g. I have a page with multiple components and they all need populating.
class SomePage extends React.Component {
constructor(props) {
super(props);
this.state = {compOneData:'', compTwoData:''};
}
componentDidMount(){
this.loadData();
}
loadData(){
fetch(someApiURL)
.then(result=>result.json())
.then(result=>this.setState({compOneData: result});
fetch(someotherApiURL)
.then(result=>result.json())
.then(result=>this.setState({compTwoData: result});
}
render(){
return (
<div>
<ComponentOne data={this.state.compOneData} />
<ComponentTwo data={this.state.compTwoData} />
</div>
);
}
}
export default SomePage;
What happens here is that when SomePage loads, the componentDidMount method is called. There are now two fetch calls in here and they will be called in parallel. React setState will then handle the data returned by the APIs. Once setState has completed, React notes the change in state and pushes the data to the two child components. This is a trivial example and doesn't explain how to handle situations where the second API call is dependent on data from the first, but should give you enough to go on.
I am very confused by what I am getting from my code. I have the following which should log out data.points then set this.state.points to data.points and then log out this.state.points, however when it logs them out they are not equal. This is the exact code I am using, so I am sure it is what was outputted. I am probably overlooking something, but I have spent the past hour reading over and logging out this code, and I still cannot figure it out. Here is the code that I run:
console.log(data.points);
if (!this.state.hasPressed) {
this.setState({points: data.points})
console.log('in not hasPressed if');
}
console.log(this.state.points);
However in the chrome remote debugger I get this:
["114556548393525038426"]
in not hasPressed if
[]
setState is an asynchronous call. you have to use function callback to wait for setState complete.
console.log(data.points);
if (!this.state.hasPressed) {
this.setState({points: data.points}, () => {
console.log(this.state.points);
});
console.log('in not hasPressed if');
}
refer to react-native setState() API:
setState(updater, [callback])
setState() does not always immediately update the component. It may
batch or defer the update until later. This makes reading this.state
right after calling setState() a potential pitfall. Instead, use
componentDidUpdate or a setState callback (setState(updater,
callback)), either of which are guaranteed to fire after the update
has been applied. If you need to set the state based on the previous
state, read about the updater argument below.
I'm using node-wit to develop a chatbot application.
This is working fine mostly, but I've run into a problem with the use of the context.
I'm using the runActions api :
this.witClient.runActions(customer._key, messageText, witContext).then((newContext => {}
)).catch(reject);
I have defined a number of actions, which set the context.
This is working fine, as long the context is taking place over one message.
For example, if I were to call an action called addProduct :
addProduct({sessionId, context, text, entities}) {
return new Promise((resolve, reject) => {
context.product = `myNewProduct';
resolve(context);
});
},
It will then show a message using the 'product' context key.
However, when I try to use it over 2 messages, it seems to have lost the context ( for example, when asking a multiple choice question, and then handling that response ).
If I understand how it's working correctly, then node-wit doesn't keep the context beyond messages ( I assumed this at first because I'm passing a session key ).
A solution I see is to store the resulting context ( newContext in this case) in a session/user specific way, and then restore it and pass it again when the user is sending his new message.
Meaning, something like this :
witContext = getContextFromSession();
this.witClient.runActions(customer._key, messageText, witContext).then((newContext => { setContextInSession(newContext) }
)).catch(reject);
Would this be the correct way of handling it ?
Off course you have to store your context state, you decide how to store it. But, take into account what is the most efficient way if you're gonna have a lot of users, and your reasources available.
As you can see in the official example for nodeJs, there's a method named findOrCreateSession on https://github.com/wit-ai/node-wit/blob/master/examples/messenger.js they get the session before the wit actions are called.
In my particular case, I am storing it in the database, so I get the session before the action is called, so I can send the context, then in the actions I query the session again to modify the resulting context and store it again, try the best implementation for your needs.
I've written a Firefox addon for the first time and it was reviewed and accepted a few month ago. This add-on calls frequently a third-party API. Meanwhile it was reviewed again and now the way it calls setInterval is criticized:
setInterval called in potentially dangerous manner. In order to prevent vulnerabilities, the setTimeout and setInterval functions should be called only with function expressions as their first argument. Variables referencing function names are acceptable but deprecated as they are not amenable to static source validation.
Here's some background about the »architecture« of my addon. It uses a global Object which is not much more than a namespace:
if ( 'undefined' == typeof myPlugin ) {
var myPlugin = {
//settings
settings : {},
intervalID : null,
//called once on window.addEventlistener( 'load' )
init : function() {
//load settings
//load remote data from cache (file)
},
//get the data from the API
getRemoteData : function() {
// XMLHttpRequest to the API
// retreve data (application/json)
// write it to a cache file
}
}
//start
window.addEventListener(
'load',
function load( event ) {
window.removeEventListener( 'load', load, false ); needed
myPlugin.init();
},
false
);
}
So this may be not the best practice, but I keep on learning. The interval itself is called inside the init() method like so:
myPlugin.intervalID = window.setInterval(
myPlugin.getRemoteData,
myPlugin.settings.updateMinInterval * 1000 //milliseconds!
);
There's another point setting the interval: an observer to the settings (preferences) clears the current interval and set it exactly the same way like mentioned above when a change to the updateMinInterval setting occures.
As I get this right, a solution using »function expressions« should look like:
myPlugin.intervalID = window.setInterval(
function() {
myPlugin.getRemoteData();
},
myPlugin.settings.updateMinInterval * 1000 //milliseconds!
);
Am I right?
What is a possible scenario of »attacking« this code, I've overlooked so far?
Should setInterval and setTimeout basically used in another way in Firefox addons then in »normal« frontend javascripts? Because the documentation of setInterval exactly shows the way using declared functions in some examples.
Am I right?
Yes, although I imagine by now you've tried it and found it works.
As for why you are asked to change the code, it's because of the part of the warning message saying "Variables referencing function names are acceptable but deprecated as they are not amenable to static source validation".
This means that unless you follow the recommended pattern for the first parameter it is impossible to automatically calculate the outcome of executing the setInterval call.
Since setInterval is susceptible to the same kind of security risks as eval() it is important to check that the call is safe, even more so in privileged code such as an add-on so this warning serves as a red flag to the add-on reviewer to ensure that they carefully evaluate the safety of this line of code.
Your initial code should be accepted and cause no security issues but the add-on reviewer will appreciate having one less red flag to consider.
Given that the ability to automatically determine the outcome of executing JavaScript is useful for performance optimisation as well as automatic security checks I would wager that a function expression is also going to execute more quickly.