I am new to React. I am trying to build a page and having like 3 button or img on main page. When I click either one, I shall be routed to another class component. You can treat it like click the icon and route you to another category page (just an example). Below is my structure and partial code I tried. I have no idea how to achieve that, and I googled and seems cannot find the stuff I want.
Structure:
/src
.index.js
.App.js
.BookStore.js
.FruitStore.js
.FoodStore.js
index.js
import React from "react";
import { render } from "react-dom";
import App from "./App";
render(
<App />,
document.getElementById('root')
);
App.js:
import React from "react";
import BookStore from "./BookStore";
const AppContainer = () => {
return (
//do the routing
<BookStore/>
)
};
export default AppContainer;
BookStore.js
export default class BookStore extends React.Component {
}
const contentDiv = document.getElementById("root");
const gridProps = window.gridProps || {};
ReactDOM.render(React.createElement(BookStore , gridProps), contentDiv);
First, you could have a look at the/one react router, e.g. https://reactrouter.com/web/guides/quick-start
However, since you're writing you're new to react, this might be a little too much ...
First, I was wondering why you're using the "ReactDOM" in your indexjs (that seems to be correct), but also in the BookStore.js. I would also recommend to write your components as functions, like your "AppContainer" and not use the class components anymore (or do you really need to do that? - why?). You can use hooks instead to have e.g. state in the components.
You would then need any kind of state in your AppContainer which is used for the routing. Maybe like this:
const AppContainer = () => {
const [showDetail, setShowDetail] = useState();
return <>
{!showDetail && <BookStore onDetail={detail => setShowDetail(detail)} />}
{showDetail && <DetailPage detail={showDetail} onBack={() => setShowDetail(undefined)}}
</>
}
Your AppContainer then has a state wheter or not to show the Bookstore (which is shown when "showDetail" is falsy, or a DetailPage which is shown when showDetail is truthy.
For this to work, your Bookstore needs to provide callbacks to let the AppContainer know that something should change. Very simply it could look like this:
const BookStore = ({onDetail}) => {
return <button onClick={() => onDetail("anything")}>Click me</button>
}
Now when someone clicks the button on the bookstore, it calls the "onDetail" callback, which was set in the AppContainer to set the "showDetail" state. So this one will be updated to "anything" in this case. This will result in a rerender on the AppContainer which will now render a DetailPage component instead.
Related
I'm going through this article and I'm trying to figure out how the persistence is supposed to occur in Option 4. From what I can tell, you'd need to redefine the .getLayout for every page. I'm not sure how the logic for nesting is incorporated into further urls.
Here's the code from the article
// /pages/account-settings/basic-information.js
import SiteLayout from '../../components/SiteLayout'
import AccountSettingsLayout from '../../components/AccountSettingsLayout'
const AccountSettingsBasicInformation = () => <div>{/* ... */}</div>
AccountSettingsBasicInformation.getLayout = page => (
<SiteLayout>
<AccountSettingsLayout>{page}</AccountSettingsLayout>
</SiteLayout>
)
export default AccountSettingsBasicInformation
// /pages/_app.js
import React from 'react'
import App from 'next/app'
class MyApp extends App {
render() {
const { Component, pageProps, router } = this.props
const getLayout = Component.getLayout || (page => page)
return getLayout(<Component {...pageProps}></Component>)
}
}
export default MyApp
For example, say AccountSettingsBasicInformation.getLayout is /settings/, how would I use this template to produce something at /settings/username
P.S. If someone has done something in the past they'd recommend over this, I'm open to ideas.
Yes, you have to redefine the getLayout function to every page. As long as the SiteLayout component stays “unchanged” (eg.no props change) the rendered content in that layout component (not the page content itself) stays persistent. This is because React wont rerender that component.
I used Adam’s article when I was building next.js lib for handlin modal routes. You can check the example folder where you can see I am defining the getLayout property on every page which should be rendered with layout.
Example: https://github.com/svobik7/next-bodies/tree/master/example
I would like to refactor my Next.js webapp to have different pages handle different screens. Currently, I have this component holding several states to know in which screen I'm in. In the jsx section, I'm using {value && ... } to render the right component.
But I feel this is not good design, and won't be maintainable when adding more and more screens.
I would also like to avoid Redux as it is overkill for my project.
I was thinking about persisting data in cookies so I can retrieve them with getInitialProps in every component when rendering a new page, but is there a more elegant way?
I've read about tweaking the _app.js but I'm not sure to understand the consequences of doing so, and how it could help me..
Any suggestion?
When multiple of your pages need to make use of same data, you can make use of Context to store the result. It a good way to make a centralized storage without using complex and more self sufficient libraries like redux
You can implement context inside of _app.js file which must reside inside your root folder. This way next.js treats it as a root wrapper and you would just need to use 1 instance of Context
contexts/appContext
import React from 'react';
const AppContext = React.createContext();
export const AppProvider = AppContext.Provider;
export const AppConsumer = AppContext.Consumer;
export default AppContext;
_app.js
import React from 'react'
import App from 'next/app'
import AppProvider from '../contexts/appContext';
class MyApp extends App {
state={
data:[]
}
render() {
const { Component, pageProps } = this.props;
// You can implement logic in this component to fetch data and update state
return (
<div>
<AppProvider value={this.state.data}> // pass on value to context
<Component {...pageProps} />
</AppProvider>
</div>
)
}
}
export default MyApp
Now further each component can make use of context value by using AppConsumer or using useContext if you use hooks
Please read more about how to use Context here
I am making a container for a d3 line graph that I'm going to create, my format so far is this:
import React from "react";
import AnalyticPads from "../AnalyticPad/AnalyticPad";
import Pad from "../AnalyticPad/Pad";
import MainContent from "../AnalyticPad/MainContent";
import Extention from "../AnalyticPad/Extention";
const GraphPad = () => {
return (
<AnalyticPads properties={{height: "200px"}}>
<Pad>
<MainContent>
</MainContent>
<Extention>
</Extention>
</Pad>
</AnalyticPads>
)
}
export default GraphPad;
And my "AnalyticsPad" looks like this:
import React from "react";
const AnalyticPads = (props) => {
return (
<div className="analytic-pad-container">
{props.children}
</div>
)
}
export default AnalyticPads;
What I want is that there will be a grid of "Pads" and I want this "AnalyticsPad" to provide default styles for each pad, for example if I want each pad to have a height of 200px I set it in this wrapper and then for any individual pad that I want to differ from the default I can overide it.
The "MainContent" component is where the line graph will be and any extra information will be put inside the "Extention" which will render if a button is pressed.
Throughout my react app I keep using the context api to provide the data to the children components, but I know ( or think ) it is bad practice to do this, from what I understand context should only be used for providing data to global components.
What is best practice?
please don't answer with a solution for class components as I have never used them before as I am new to react.
I have a trouble regarding this issue on react native navigation by the way I am using redux.
Listserviceaction.js
contains webservicecall component is being imported here
import ListComponent from '../components/ListComponent';
Listactiontype.js
contains action ActionTypes
export const SERVICE_PENDING = 'service_pending' and etc.
listcomponent.js
the component, renders data on a list etc
reducers
and then the reducer Part
scenes/List.js
store binding will be done within the initial point of the application and passed down to the other application components as shown below.
import React, { Component } from 'react';
import { Provider } from 'react-redux';
import store from '../reducers/index';
import ServiceAction from '../actions/listserviceaction';
import { Container, Content, Picker, Button, Text } from "native-base";
export default class RenderList extends Component {
render() {
return (
<Provider store={store}>
<ServiceAction />
</Provider>
);
}
}
now after the component is being loaded and when i click onPress={() => this.props.navigation.navigate("ProfileScreen")} on my
listcomponent it fires an error (undefined is not an object .. this.props.navigation.navigate) any problem ? any better solution?
Thank You.
Include on your ServiceAction the this.props.navigation something like this:
<ServiceAction navigation={this.props.navigation}/>
because the props.navigation are by default on your parent component
and on ServiceAction component you will access to navition like:
..
goToSignUp() {
this.props.navigation.navigate('SignUp');
}
..
For me also was confusing before. Cheers!
for navigating from one screen to other, both the screens should be in StackNavigator. Can you please show your stacknavigator and code of the screens you are trying to navigate between.
for using react navigation you must do this steps:
1: npm i react-navigation --save
2: npm link react-navigation
3: modify a top level class for your stack like this :
import page_1 from 'YOUR_PAGE1_PATH'
import page_2 from 'YOUR_PAGE2_PATH'
import { createStackNavigator } from 'react-navigation'
export default createStackNavigator({
p1 : page_1 //remember the first modified shown first
p2 : page_2
})
then in page_1 if you want to navigate to page 2 :
onPress(()=> this.props.navigation.navigate('p2' , 'maybe other params'))
Note : you must call p1,p2 instead of page_1 or page_2!
I'm trying to create an Electron app using React, React-router and Redux. What I'm finding is that my routing logic works absolutely fine when I'm nesting the switch/route logic under a purely presentational component (Page), but that I'm forced to refresh the page to see navigational changes if nested under a 'smart' container component.
Near the top of my React component hierarchy (right beneath HashRouter) I have a Page:
export default function Page (props) {
return (
<div className={`${styles.page}`}>
<SideBar/>
<DetailPane>{props.children}</DetailPane>
</div>
);
}
Here, DetailPane and SideBar are both container components wrapped around presentational components of the same name.
At startup (and during hot reloads), I create my React hierarchy using this function:
export default () => (
<Router>
<Page>
<Switch>
<Route exact path='/txDefinitions/:definitionName/:fieldName' component={FieldPage}/>
<Route exact path='/txDefinitions/:definitionName?' component={DefinitionPage}/>
<Route exact path='/rxDefinitions/:definitionName?' component={DefinitionPage}/>
<Route exact path='/'/>
<Route component={Route404}/>
</Switch>
</Page>
</Router>
This means that <Switch>...</Switch> gets nested underneath <DetailPane>.
If I try to navigate around my app (clicking links in the side bar), I won't actually see the detail pane render the new component until I force-reload the Electron app.
However, I find that routing works as expected if I omit DetailPane from Page:
export default function Page (props) {
return (
<div className={`${styles.page}`}>
<SideBar/>
{props.children}
</div>
);
}
Here is my React hierarchy without DetailPane (works fine):
Here is my React hierarchy with DetailPane (does not work right):
(Apologies for using images but I'm not sure if there's a way to copy from React devtools into clipboard - appears larger if opened in a new tab).
As I was writing this question, I realised this wouldn't be a huge issue for me because earlier refactoring had made the 'smart' version of DetailPane apparently obsolete. Using the purely presentational version of DetailPane
instead resolves this issue:
import * as React from 'react';
//import {DetailPane} from '../../containers'; // Smart/Redux
import {DetailPane} from '../../components'; // Dumb/presentational
import {SideBar} from '../../containers/';
const styles = require('./Page.scss');
export default function Page (props) {
return (
<div className={`${styles.page}`}>
<SideBar/>
<DetailPane>{props.children}</DetailPane>
</div>
);
}
However, I'm still curious why this doesn't work for the container component version. For reference, this is the container component version of DetailPane:
import {connect} from 'react-redux';
import {DetailPane} from '../../components';
// TODO: delete this container?
function mapStateToProps (state): {} {
return {};
}
function mapDispatchToProps (dispatch) {
// TODO.
return {};
}
export default connect(mapStateToProps, mapDispatchToProps)(DetailPane);
The connect HOC implements shouldComponentUpdate logic so if the props don't change, the component doesn't update.
To prevent this from occurring, and have the component always render, you can override the pure option in the connect call.
export default connect(mapStateToProps, mapDispatchToProps, undefined, { pure: false })(DetailPane);
See the react-redux API docs for more details.