I need advice on how to pass a Reactjs prop from a component to my app when it's loaded. I'm able to pass the value when my props are in app.js but how do I handle the prop when loading from a separate component?
Here's what's working so far in app.js:
import React, { PropTypes, Component } from 'react';
import { Grid, Nav, Navbar, NavItem, Jumbotron } from 'react-bootstrap';
import { Link } from 'react-router';
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
function HeaderTitle(props) {
return <h1>{props.name}</h1>;
}
const headerTitle = <HeaderTitle name="About Page" />;
class App extends React.Component {
constructor(props) {
super(props);
}
render() { ...
<p>{headerTitle.props.name}</p>
Parent to Child
If you want to pass all the props through:
render() {
return (
<div>
<HeaderTitle {...this.props} />
</div>
);
}
Or if just some:
render() {
return (
<div>
<HeaderTitle name={this.props.name} />
</div>
);
}
Child to Parent
If you mean the other way round, you need to use a callback
// app
render() {
return (
<div>
<HeaderTitle onGetName={(name) => this.setState({childName: name})} />
<p>{this.state.childName}</p>
</div>
);
}
// headertitle
componentDidMount() {
// maybe some async call or something
axios
.get('/api/say-my-name')
.then(response => this.props.onGetName(response.data);
}
So I guess you need some thing like importing components from one file to another. So you have options to import and export components from another file since React components are basically Objects. In index.js if you have something like
const headerTitle = <HeaderTitle name="About Page" />;
export default headerTitle;
and in app.js
import React, { PropTypes, Component } from 'react';
import { Grid, Nav, Navbar, NavItem, Jumbotron } from 'react-bootstrap';
import { Link } from 'react-router';
import { LinkContainer, IndexLinkContainer } from 'react-router-bootstrap';
import HeaderTitle from '/// put the file relative location to app.js"
function HeaderTitle(props) {
return <h1>{props.name}</h1>;
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() { ...
<p>{headerTitle.props.name}</p>
}
Related
I am trying to understand how to pass props to components in react. I am new to react and I have been struggling to understand the fundamentals of state.
I would like a button to display an overlay and populate the "content" of that overlay with some arbitrary text for now.
I am trying to use a prop called doWeDisplay as variable to hold a css value of "none" or "absolute" (to hide and show the component) and a prop called "content" for the content of the overlay.
Here is my code, could someone please point me in the right direction. I need that eureka moment for it to click in place and my head is all over the place trying to get this.
app.js
import React from 'react';
import Overlay from './components/overlay';
import Header from './components/header';
import Body from './components/body';
import Footer from './components/footer';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
console.log("App props", this.props)
return (
<div className="App">
<Overlay />
<Header />
<Body content={ this.props.appContent } />
<Footer />
</div>
);
}
}
export default App;
body.js
import React from 'react';
import './body.css';
import Overlay from './overlay'
class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay : "absolute",
content : "Go on"
};
}
render() {
function handleClick(e) {
console.log("Click")
Overlay.setState((state, props) => ({
doWeDisplay : "absolute",
content : "Go on"
}))
}
console.log("Body props ", this.props);
return (
<div className="App-Body">
<p>Here is the body of the page.</p>
<button onClick={ handleClick }>Click me</button>
</div>
);
}
}
export default Body
overlay.js
import React from 'react';
import './overlay.css';
class Overlay extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay : props.doWeDisplay,
content : props.doWeDisplay
};
}
render() {
console.log("Overlay props " , this.props)
return (
<div className="App-Overlay" style={{ display: this.state.doWeDisplay }}>
{ this.state.content }
</div>
);
}
}
export default Overlay
When you have sibling components that can change other's state, you will need to handle that state in the parent component (in your case it is App).
So the handleClick() function should be in the parent component, and the state itself of the variables doWeDisplay and content should be in App as well.
Then, you can pass that function to Body as a prop, so you could trigger it on click within the Body component. I called that prop clickFunc in my example.
Finally, the last thing you will need is to pass the current state to Overlay as props, so I passed the doWeDisplay and content as different props, that gets the value from App's state.
It should look something like this:
app.js
import React from 'react';
import Overlay from './components/overlay';
import Header from './components/header';
import Body from './components/body';
import Footer from './components/footer';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
doWeDisplay: "absolute",
content: "Go on"
};
}
handleClick = () => {
console.log("Click");
this.setState({
doWeDisplay: "absolute",
content: "Go on CHANGED!"
});
};
render() {
console.log("App props", this.props);
return (
<div className="App">
<Overlay
doWeDisplay={this.state.doWeDisplay}
content={this.state.content}
/>
<Body clickFunc={this.handleClick} content={this.props.appContent} />
</div>
);
}
}
export default App;
body.js
import React from 'react';
import './body.css';
import Overlay from './overlay'
class Body extends React.Component {
render() {
console.log("Body props ", this.props);
return (
<div className="App-Body">
<p>Here is the body of the page.</p>
<button onClick={() => this.props.clickFunc()}>Click me</button>
</div>
);
}
}
export default Body
overlay.js
import React from 'react';
import './overlay.css';
class Overlay extends React.Component {
render() {
console.log("Overlay props ", this.props);
return (
<div className="App-Overlay" style={{ display: this.props.doWeDisplay }}>
{this.props.content}
</div>
);
}
}
export default Overlay
Here's codesandbox
Parent Component
import React, {Component} from 'react';
import NameContainer from '../nameContainer/index'
export default class Vishal extends Component {
constructor(props) {
super(props);
this.state = {
data: "This is the data"
}
}
render() {
return(
<div>
<p>My name is Vishal</p>
</div>
)
}
}
Child Component
import React, {Component} from 'react';
export default class NameContainer extends Component {
}
How can I use a callback function and import from the child component? Any help will be highly appreciated
This violates the top-down philosophy of react and any sort of way to hijack that is probably not the direction you want to go.
What I think you mean to do is have state in the parent container, and allow the child to display and update that state.
i.e Parent.JS
import React, {Component} from 'react';
export default class NameContainer extends Component {
this.state = { name: 'Vishal' }
handleChange = this.setState({name: event.target.value})
render() {
return (
<Vishal name={this.state.name} handleChange={this.handleChange} /> )}
then in child js // Vishal.js
{ ...boilerplate }
handleChange = this.props.handleChange; // and e.g a button or textfield to allow the user to update the name.
render() {
return ( {this.props.name}) }}
this will display the stateful data of name (initalized as 'Vishal') from Parent.js in the child component, Vishal.js
I've created a React Native app with navigation provided by react-navigation, also integrating redux with react-navigation-redux-helpers, and I'm trying to figure out a good way of implementing a globally-available 'SignOutHeaderButton' component that, when pressed, will dispatch a redux action and perform a navigation operation.
At the moment, I'm having to pass a function via screenProps from the application root component, which is the function that dispatches the redux action. This function is then passed to the UpdatesListView container component via screenProps, and is then passed into the SignOutHeaderButton common component as a prop via navigationOptions.
Is there a better way in which I can implement this so that I don't have to pass any props into the SignOutHeaderButton component and without having to instantiate a signOut() function within each container component in the application from which there will be a 'Sign Out' button?
App.js:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import { reduxifyNavigator } from 'react-navigation-redux-helpers';
import { PersistGate } from 'redux-persist/integration/react';
import { Provider, connect } from 'react-redux';
import { appContainer } from './src/navigators';
import { store, persistor } from './src/store/configureStore';
import { signOut } from './src/actions/auth';
const app = reduxifyNavigator(appContainer, 'root');
const mapStateToProps = state => {
return {
state: state.navReducer
}
}
const AppWithNavigationState = connect(mapStateToProps)(app);
export default class App extends React.Component {
signOut() {
store.dispatch(signOut());
}
render() {
return (
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<AppWithNavigationState
screenProps={{
signOut: this.signOut
}} />
</PersistGate>
</Provider>
)
}
}
UpdatesListView.js:
import React from 'react';
import { View, Container, Content, Text, Button } from 'native-base';
import { connect } from 'react-redux';
import SignOutHeaderButton from '../components/common/SignOutHeaderButton';
class UpdatesListView extends React.Component {
constructor(props) {
super(props);
}
static navigationOptions = ({ navigation }) => {
return {
headerTitle: 'Updates',
headerRight: <SignOutHeaderButton signOut={navigation.getParam('signOut')} />
}
}
componentDidMount() {
this.props.navigation.setParams({
signOut: this.props.screenProps.signOut
})
}
render() {
return (
<Container>
<Text>UpdatesListView</Text>
</Container>
)
}
}
const mapStatetoProps = state => {
return {
updates: state.updatesReducer,
tags: state.tagsReducer
}
}
export default connect(mapStateToProps)(UpdatesListView);
SignOutHeaderButton.js:
import React from 'react';
import { Button } from 'react-native';
import { withNavigation } from 'react-navigation';
class SignOutHeaderButton extends React.Component {
constructor(props) {
super(props);
}
signOut() {
this.props.signOut();
this.props.navigation.navigate('AuthStack');
}
render() {
return (
<Button
title="Sign Out"
onPress={this.signOut} />
)
}
}
export default withNavigation(SignOutHeaderButton);
Use redux connect, the idea of redux connect is to bind the store dispatch state to your component this, When you use redux connect you can access any redux store dispatch and state from anywhere in your application this works for both react and react-native, for example for SignOutHeaderButton.js:
import React from 'react';
import { Button } from 'react-native';
import { connect } from 'react-redux';
import { withNavigation } from 'react-navigation';
class SignOutHeaderButton extends React.Component {
constructor(props) {
super(props);
}
signOut() {
this.dispatch(signOut());
this.props.navigation.navigate('AuthStack');
}
render() {
return (
<Button
title="Sign Out"
onPress={this.signOut} />
)
}
}
export default connect()(withNavigation(SignOutHeaderButton));
Also, you can pass the redux store state to your component by passing a function to your connect(/*your function*/) to resolve the state data you want.
for better understanding, you can try this tutorial: https://blog.logrocket.com/react-redux-connect-when-and-how-to-use-it-f2a1edab2013
Note using nested smart components is very common, redux connect has a very smart algorithm to compare the store state changes, please check this: https://hackernoon.com/why-using-nested-connect-react-redux-components-is-good-bd17997b53d2
for starting, i saw many questions which looks like mine on stackoverflow but i think i miss something, this is why i'm asking this question.
I have a Maincomponent in my app which add datas to my store using the action addDatas.
This part works, i can access to my store in the context and in the children of MainComponent with this.props.
But when i go to OtherComponent (which is a basic component where i just want to show all the datas collected in MainComponent) my store seems to be empty.
Can someone tells me what i'm doing wrong and what OtherComponent should looks like for access the datas i set in the store when i was using MainComponent.
Thanks.
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './components/App';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import reducer from './reducers'
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
reducers.js
import { ADD_DATAS } from '../constants';
const reminder = (action) => {
switch (action.type) {
case ADD_DATAS:
return {
datas: action.datas,
id: action.id
};
default:
return {
text: action.text,
id: action.id
};
}
}
const reminders = (state = [], action) => {
let reminders = null;
switch (action.type) {
case ADD_DATAS:
reminders = [...state, reminder(action)];
return reminders;
default:
return state;
}
}
export default reminders;
Action.js
import {ADD_DATAS} from '../constants';
// ADD_DATAS = 'ADD_DATAS' in constants
export const addDatas = (text, id) => {
const action = {
type: ADD_DATAS,
datas: text,
id: id
}
return action;
}
App.js
import React, { Component } from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import RouterComponent from '../Router/RouterComponent';
import OtherComponent from './OtherComponent';
import MainComponent from './MainComponent';
class App extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
<Sidebar />
<Router>
<RouterComponent>
<Switch>
<Route exact path="/oth" component={OtherComponent}/>
<Route exact path="/main" component={MainComponent}/>
<Route exact path="/" component={MainComponent}/>
</Switch>
</RouterComponent>
</Router>
</div>
</div>
);
}
}
export default App;
MainComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { addDatas } from '../actions'
class MainComponent extends Component {
addDataStore(text, id){
this.props.addDatas(text, id)
}
render(){
return ( .... )
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({addDatas}, dispatch);
}
function mapStateToProps(state){
return {
reminders: state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MainComponent);
OtherComponent.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
class OtherComponent extends Component {
render(){
console.log(this.props.reminders)
}
}
function mapStateToProps(state){
return {
reminders: state
}
}
export default connect(mapStateToProps)(OtherComponent);
Sidebar.js
import React, { Component } from 'react';
import '../css/sidebar.css';
export default class Sidebar extends Component {
render(){
return (
<nav className="col-2 col-md-2 sidebar">
<div className="sidebar-logo">
<a href="/main">
MainComponent
</div>
</a>
</div>
<ul >
<li >
<a href="/main" >
MainComponent
</a>
</li>
<li >
<a href="/oth" >
OtherComponent
</a>
</li>
</ul>
</nav>
)
}
}
To Understand this we first need to understand the below snippet
export default connect(mapStateToProps, mapDispatchToProps)(MainComponent);
we are passing mapStateToProps function to the connect method which we get from react-redux. So let's Understand how connect works and what it actually does
1. It calls your mapStateToProps function and passes the current value of (redux state/ redux store) to the function.
2. Then whatever value is returned by the mapStateToProps function after execution is passed down as props to the mainComponent(in your case).
So Since the child component for the main component is not having connect statement the props are not available to it.
You can make the redux state available as props by two was
1. Passing it down from main component as follows inside mainComponent.js render method we have
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { addDatas } from '../actions'
class MainComponent extends Component {
addDataStore(text, id){
this.props.addDatas(text, id)
}
render(){
return (
<Child1 reminders={this.props.reminders}/*can be accessed as this.props.reminders*//>
<Child2 reminders={this.props.reminders}/*can be accessed as this.props.reminders*//>
)
}
}
function mapDispatchToProps(dispatch){
return bindActionCreators({addDatas}, dispatch);
}
function mapStateToProps(state){
return {
reminders: state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(MainComponent);
2.Another way to do this will be using connect Statement inside your child component as well
export default connect(mapStateToProps, mapDispatchToProps)(MainComponent);
class Child1 extends Component{
.....
}
function mapDispatchToProps(dispatch){
return bindActionCreators({addDatas}, dispatch);
}
function mapStateToProps(state){
return {
reminders: state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Child1);//need to change here must be same as className
You should connect your OtherComponent to redux store as well using connect HoC.
You need to connect other components with mapStateToProps and mapDispatchToProps functions as you do in MainComponents.js
import React, { Component } from 'react';
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { addDatas } from '../actions'
class OtherComponent extends Component {
addDataStore(text, id) {
this.props.addDatas(text, id)
}
render() {
}
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({ addDatas }, dispatch);
}
function mapStateToProps(state) {
return {
...state
}
}
export default connect(mapStateToProps, mapDispatchToProps)(OtherComponent);
You would connect the otherComponent as well using connect HOC, in order to access the Store. Once you have a component connected the Store in the Hierarchy you can pass the data as props on to its children. However you do need to connect the top level component/s to store
import React, { Component } from 'react';
import { connect } from 'react-redux'
class OtherComponent extends Component {
render(){
console.log(this.props.reminders)
}
}
function mapStateToProps(state){
return {
reminders: state
}
}
export default connect(mapStateToProps)(OtherComponent);
Well,
my problem wasn't on my implementation of Redux but on the fact that i used href for navigate between my components.
The problem was that my Sidebar component wasn't in the Router component, then i had to save the history in the redux store and call history.push in my sidebar component with the history i saved before.
In all my components inside the router i added in the constructor:
constructor(props){
super(props);
...
this.props.addHistory(props.history);
}
addHistory add history if it doesn't already exist.
Then in my sidebar, i use the history in the store for use the push function:
for (var e in this.props.reminders){
if(this.props.reminders[e].history !== undefined ){
this.props.reminders[e].history.push('/oth');
}
}
I don't know if it's the cleanest way to do this, but it works.
For example, a component like this:
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
render() {
return (
<div className="App">
<BodyContent />
<BottomOne />
</div>
);
}
}
export default App;
I want to implement a function on BodyContent that unmount BottomOne and mounts BottomTwo instead, so when I activate the function, the code is reestructured to this:
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
render() {
return (
<div className="App">
<BodyContent />
<BottomTwo />
</div>
);
}
}
export default App;
I'm very new to React, so if there's a better way to do it, I'm open to suggestions, but I really need that end result, a function on BodyContent that unmounts BottomOne and mounts BottomTwo.
You can maintain a state which tells which component to render. Something roughly like this
import React, { Component } from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
changeBottomComponent = (comp) => {
this.setState({ showBottom: comp})
}
render() {
return (
<div className="App">
<BodyContent changeBottomComponent={this.changeBottomComponent}/>
{this.state.showBottom === 1 ? <BottomOne /> : <BotttomTwo />}
</div>
);
}
}
export default App;
To achieve that maintain a state variable in parent component (some kind of identifier for component) and use that state variable to render different component.
Along with that you also need to pass a function from parent to child and use that function to update the parent state value.
Like this:
class App extends Component {
constructor(){
super();
this.state={
renderOne: true,
}
this.update = this.update.bind(this);
}
update(){
this.setState({renderOne: false})
}
render() {
return (
<div className="App">
<BodyContent update={this.update}/>
{this.state.renderOne? <BottomOne /> : <BottomTwo/> }
</div>
);
}
}
Now inside BodyContent component call this.props.update() to render another component.
You can use state or props to render different components.
Example:
import React, {
Component
}
from 'react';
import BodyContent from './BodyContent';
import BottomOne from './BottomOne';
import BottomTwo from './BottomTwo';
class App extends Component {
constructor(props) {
super(props);
this.state = {
decider: false
};
}
render() {
const bottomContent = this.state.decider === true ? <BottomOne /> : <BottomTwo />;
return (
<div className="App">
<BodyContent />
{ bottomContent }
</div>
);
}
}
export
default App;
You can also directly use the components in the state and render them. Could be more flexible this way.
const BottomOne = () => <div>BottomOne</div>;
const BottomTwo = () => <div>BottomTwo</div>;
class Example extends React.Component {
constructor() {
super();
this.state = { show: BottomOne };
this.toggleComponent = this.toggleComponent.bind(this);
}
toggleComponent() {
// Use whatever logic here to decide.
let show = BottomOne;
if (this.state.show === BottomOne) {
show = BottomTwo;
}
this.setState({ show });
}
render() {
return (
<div>
<button onClick={this.toggleComponent}>Change</button>
<this.state.show />
</div>
);
}
}
ReactDOM.render(<Example />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>