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.
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)
}
}
Tech stack - Node.js, MongoDB for the database, Strapi CMS for editing and API, React - my application.
I have a database with a long list of entries and a ready-to-use application that allows users to read data from the database. I need to be able to generate a simple website with a single entity from my database as a source to fill the template.
Mockup
Here is a mock-up. Hopefully, it will make things a bit clearer.
Clarification
After a day of thinking about the task, I believe I need something like a simplest static website generator - an application that will allow me to select a single bit of data from the list and generate a small website filled with it. The end goal is to get a website in some subfolder of my application where I can get it and use it however I need.
A bit more about specifics:
It will be used locally
Security can be neglected
Running always in development is not a problem (just in case, thinking about additional question #2)
Few additional questions:
Is it possible to run NPM scripts from the application (like npm build)
Is there any way to show one component in development mode, but replace it with another during building for production?
App.js
//...
function App() {
if() {
return <AdminUI /> // This one is to be shown in development mode
} else {
return <Website /> // This one is to be used instead of AdminUI in the build
}
UPDATE
Well, I'm digging a path to create a site generator and so far I come up with the following basic plan:
Get my template ready
Create a new directory for my website
Copy a template to the new folder
Get an HTML file, parse it to a string to modify
Swap some bits with my data
Save to a file from the modified string
repeat if needed for other files.
If that works as expected, the whole process probably might be improved by moving from a fixed template to a component, that will be prepared with a JavaScript bundler and started with the help of something like node-cmd (to run shell commands from my application)...
What you want could be achievable, but if it's just a string and little else, I'd say it's much simpler to fetch the data at startup from a given file, and populate from there. You can put a JSON file under the public folder (together with other static data, like images) and have the file being your configuration.
In the App.js file, write an async componentDidMount() and you can do an await axios.get("") with your configuration.
So App.js would look like (code written on the fly, didn't check in an IDE):
export class App extends React.App {
constructor(props) {
super(props);
this.state = { loading: true, };
}
async componentDidMount() {
const response = await axios.get("your/data.json");
this.setState({ loading: false, ... whatever})
}
render = () => (
<>
(this.state.loading && <div>Still loading...</div>)
(this.state.adminData && <AdminUI data={this.state.admingData} />)
(this.state.devData && <Website data={this.state.devData} />)
</>
)
}
If you don't care about security, wouldn't be much simpler like this? And if you use TypeScript you'll have a much much simpler life in handling the data too.
Maybe it's worth doing an AdminUI to generate the JSON, and the another UI which reads the JSON, so you end up doing two UIs. The template-generated UI could even ask for a JSON file to bootstrap directly to the user, if it simplifies... In general, an approach based on simple JSON sounds a lost simpler than going for a CI/CD pipeline.
I want to use a workflow similar to the Page Object Pattern that exists in frameworks like Selenium. I want to use my login.spec.js in my editSettings.spec.js, because it requires a user to be logged in.
How do I achieve this in Cypress? Can I export a function from one test file to use in another?
Yes, Cypress supports the ability to create and reuse actions in your UI, such as logging in as a user would.
However, Cypress also allows you to control the state of the browser more powerfully than a user would.
For example: I create a test that a "user can log in with valid username and password"- Cypress navigates to the login page, types in the user field, types in the password field and clicks the "Log in" button. The Page Object Pattern would have you reuse this action on every test that requires a user to be logged in (most of the tests)
Cypress supports this; however, this is slower than it has to be. It takes a considerable amount of time to navigate to a login page, type in the information, handle the response, and navigate to the page under test.
Instead, Cypress's API allows the following:
use cy.request() to directly hit your server with the login credentials. This requires no state of your app, no typing in fields, no clicking buttons, or page directs
Any cookies your site uses are automatically set, or you can set localStorage using the response
Make this a custom command, call it before every test, and boom- you've generated your user's state almost instantly and most importantly flake-free
I actually came up with these two examples, one using JavaScript and another one with Typescript.
https://github.com/antonyfuentes/cypress-typescript-page-objects
https://github.com/antonyfuentes/cypress-javascript-page-objects
Hopefully, this helps someone else.
Create a SearchProduct.js file in fixtures folder (You can create it anywhere).Then create a class in it and define your all the methods in it something like this:
class ProductPage {
getSearchClick() {
return cy.get('.noo-search');
}
getSearchTextBox(){
return cy.get('.form-control');
}
getProductsName() {
return cy.get('.noo-product-inner h3');
}
getSelectSize() {
return cy.get('#pa_size');
}
getSelectColor() {
return cy.get('#pa_color');
}
getAddtoCartButton() {
return cy.get('.single_add_to_cart_button');
}
}
export default ProductPage
After creating the class, let's import it in the command.js file. After that, let's create a new object of it to access all the methods mentioned above in commands.js.
import ProductPage from '../support/PageObjects/ProductPage';
Cypress.Commands.add("selectProduct", (productName, size , color) => {
// Creating Object for ProductPage
const productPage=new ProductPage();
// Doing the search part for Shirts.
productPage.getSearchClick().click()
productPage.getSearchTextBox().type('Shirt');
productPage.getSearchTextBox().type('{enter}')
productPage.getProductsName().each(($el , index , $list) => {
//cy.log($el.text());
if($el.text().includes(productName)) {
cy.get($el).click();
}
})
// Selecting the size and color and then adding to cart button.
productPage.getSelectColor().select(color);
productPage.getSelectSize().select(size);
productPage.getAddtoCartButton().click();
})
So, here actually the custom command's class is importing and using the Page class. Additionally, the test script will use the same command.js to perform the needed action.
So, the test script will still be the same and will look as below:
// type definitions for Cypress object "cy"
// <reference types="cypress" />
describe('Cypress Page Objects and Custom Commands', function() {
//Mostly used for Setup Part
before(function(){
cy.fixture('example').then(function(data)
{
this.data=data ;
})
})
it('Cypress Test Case', function() {
//Registration on the site
cy.visit('https://shop.demoqa.com/my-account/');
cy.get('#reg_username').type(this.data.Username);
cy.get('#reg_email').type(this.data.Email);
cy.get('#reg_password').type(this.data.NewPassword);
cy.get('.woocommerce-Button').click();
//Checking whether the Registration is successful and whether UserName is populated under login section
cy.get('#username').should('have.value',this.data.Username);
})
// For Loop for Accessing productName array from Features File and Using the custom command
this.data.productName.forEach(function(element){
// Invoke the Custom command selectProduct
cy.selectProduct(element[0],element[1],element[2]);
})
})
You can also directly import the class in Test File by skipping Command.js file.
For that go to the following link:
Courtesy: https://softans.com/cypress-page-object-model/
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'!
I know window doesn't exist in Node.js, but I'm using React and the same code on both client and server. Any method I use to check if window exists nets me:
Uncaught ReferenceError: window is not defined
How do I get around the fact that I can't do window && window.scroll(0, 0)?
Sawtaytoes has got it. I would run whatever code you have in componentDidMount() and surround it with:
if (typeof(window) !== 'undefined') {
// code here
}
If the window object is still not being created by the time React renders the component, you can always run your code a fraction of a second after the component renders (and the window object has definitely been created by then) so the user can't tell the difference.
if (typeof(window) !== 'undefined') {
var timer = setTimeout(function() {
// code here
}, 200);
}
I would advise against putting state in the setTimeout.
This will settle that issue for you:
typeof(window) === 'undefined'
Even if a variable isn't defined, you can use typeof() to check for it.
This kind of code shouldn't even be running on the server, it should be inside some componentDidMount (see doc) hook, which is only invoke client side. This is because it doesn't make sense to scroll the window server side.
However, if you have to reference to window in a part of your code that really runs both client and server, use global instead (which represents the global scope - e.g. window on the client).
This is a little older but for ES6 style react component classes you can use this class decorator I created as a drop in solution for defining components that should only render on the client side. I like it better than dropping window checks in everywhere.
import { clientOnly } from 'client-component';
#clientOnly
class ComponentThatAccessesWindowThatIsNotSafeForServerRendering extends Component {
render() {
const currentLocation = window.location;
return (
<div>{currentLocation}</div>
)
};
}
https://github.com/peterlazzarino/client-component
<Router onUpdate={() => window.scrollTo(0, 0)} history= {browserHistory}>
if you need to open new page on top in React JS app, use this code in router.js
Move the window and related code to the mounted() lifecycle hook. This is because mounted() hook is called on the client side only and window is available there.