Ok so I have two files Test.js and Test2.js
Test.js:
import React from 'react';
const hello = ['hello', 'hi', 'sup'];
export const helloWorld = hello.map(helloCode => {
return (
<button onClick={this.handleClick}>{helloCode}</button>
);
});
Test2.js:
import React from 'react';
import { helloWorld } from './Test';
export class RealTest extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('clicked');
}
render() {
return (
<div>
{helloWorld}
</div>
);
}
};
I can't figure out how to get helloWorld to access the onClick function, I have tried to create a props, I have tried binding it, but I cannot get it to work unless it is in Test2.js, but I need it to be in it's own seperate file. Thanks for the help.
#Adam suggesting passing the context down, but I think it's more React like to pass props.
export const HelloWorld = props => hello.map(helloCode => {
return (
<button
key={helloCode} // <--- make sure to add a unique key
onClick={props.handleClick}
>
{helloCode}
</button>
);
});
Then render:
<div>
<HelloWorld handleClick={this.handleClick} />
</div>
The array of JSX accessed via the variable helloWorld does not have any knowledge of what you want the context (e.g. this) to be when it's in it's own file (and, thus, this.handleClick can't be used).
The simplest way is to make it a function so you can pass the correct context:
import React from 'react';
const hello = ['hello', 'hi', 'sup'];
export const helloWorld = (context) => hello.map(helloCode => {
return (
<button onClick={context.handleClick}>{helloCode}</button>
);
});
and then in your render method, pass in the context:
render() {
return (
<div>
{helloWorld(this)}
</div>
);
}
const hello = ['hello', 'hi', 'sup'];
const HelloWorld = (props) => <div>{hello.map(name =>(<button onClick={() => props.handleClick(name)}>{name}</button>))}</div>
class RealTest extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(name) {
console.log('clicked for name ', name);
}
render() {
return (
<div>
<HelloWorld handleClick={this.handleClick} />
</div>
);
}
};
ReactDOM.render(
<RealTest/>,
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>
Related
I currently have my Parent set up as follows, which I'm then passing props to
class WorkoutPlan extends React.Component {
constructor() {
super();
this.state = {
workoutPlan: {}
};
}
componentDidMount() {
axios
.get("/api/workout-plan")
.then(response => {
this.setState({ workoutPlan: response.data });
})
.catch(error => {
console.log(error);
});
}
render() {
const { workoutPlan } = this.state;
// const workoutPlan = this.state.workoutPlan;
return (
<div>
<h1>{workoutPlan.Name}</h1>
<button className="button" onClick={this.handleClick}>
Click Me
</button>
<Workout {...workoutPlan.workout} />
</div>
);
}
}
Then in my child, I'm wanting to pass those same props to another Child
import React from "react";
import Exercise from "./Exercise";
const Workout = props => {
return (
<div>
<h2>"Workout for {props.day}"</h2>
<Exercise {...workoutPlan.workout} />
</div>
);
};
export default Workout;
I can't seem to figure out how I would go about doing this. I'm being told that the setup is exactly the same as the 1st child, but when I enter in the same code, it's not working.
You can pass {...props} to your Exercise component so your Workout component should look like this
import React from "react";
import Exercise from "./Exercise";
const Workout = props => {
return (
<div>
<h2>"Workout for {props.day}"</h2>
<Exercise {...props} />
</div>
);
};
export default Workout;
When you pass props destructuring it, the effect it's the same as you were passing props one by one.
You can't achieve your goal because in your Workout component there is no "workout" prop.
Try to pass props to Exercise component like this:
<Exercise {...props} />
i need to know how to fetch state of component from other component by calling the seconed component method inside of first component ?
like :
class General extends Component {
state = {
input:"
}
fetchState() {
return this.state;
}
handleChange () {
this.setState({[e.target.name]: e.traget.value});
}
render() {
return <input type="text" name="input" onChange={this.handleChange.bind(this}>
}
}
class Car extends Component {
render() {
console.log( General.fetchState() );
return null;
}
}
i know i can use static method but i don't have access to this keyword.
The recommended way of doing that kind of things is by composing components and passing the parent's states as props
class General extends Component {
state = { ... }
render () {
return (
<Car {...this.state} />
)
}
}
class Car extends Component {
render () {
console.log(this.props)
return (...)
}
}
Now if you want to share a global state between components could be a good idea to use context api with hooks.
import React, { createContext, useContext } from "react";
import ReactDom from "react-dom";
const initialState = { sharedValue: "Simple is better" };
const StateContext = createContext({});
const General = () => {
const globalState = useContext(StateContext);
return <h1>General: {globalState.sharedValue}</h1>;
};
const Car = () => {
const globalState = useContext(StateContext);
return <h1>Car: {globalState.sharedValue}</h1>;
};
const App = () => {
return (
<StateContext.Provider value={initialState}>
<General />
<Car />
</StateContext.Provider>
);
};
ReactDom.render(
<App />,
document.getElementById("root")
);
Here is the example link.
And here I have a repo with a more elaborated example managing global state with just hooks.
There are many approaches, I suggest using a general state accessible from both components.
Check ReactN for simplicity or Redux for a more robust solution. Note Redux has a big learning curve and quite some boilerplate that, depending on the size of your App, it could not be necessary.
Using globals is not advisable on many situations, but to answer your question, you could also do this:
General component:
class General extends Component {
constructor(){
global.fetchGeneralState = this.fetchState;
}
fetchState = () => {
return this.state;
}
}
Then from the Car component, you can just call: global.fetchGeneralState(); and you will get the state from the General component.
In your current code, the only way to do it is to use new General.
console.log(new General().fetchState());
If you expect to use Car component as a parent of General component, then you can simply use ref. Here is the modified code of yours that I have tested :
import React from "react";
class General extends React.Component {
constructor () {
super();
this.state = {input: ""}
this.handleChange = this.handleChange.bind(this);
}
fetchState() {
return this.state;
}
handleChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return <input type="text" name="input" onChange={this.handleChange} />
}
}
export default class Car extends React.Component {
constructor () {
super();
this.refToGeneral = React.createRef()
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
console.log(this.refToGeneral.current.fetchState())
}
render() {
return (
<>
<General ref={this.refToGeneral} />
<button type="button" onClick={this.handleClick}>Show State</button>
</>
)
}
}
I'm learning React and I need help understanding how to create functions for values that are updated asynchronously in the DOM. For instance, I have a text input within a component called header that looks like this:
export default class Header extends React.Component {
constructor(props){
super(props);
}
render(){
return (
<div className="Header">
<div><input onKeyDown={this.props.onEnter} id="filter-results" className="full" type="text" placeholder="search kks"></input></div>
<div><button className="full">SEARCH</button></div>
</div>
);
}
}
, which is used to filter search results. The onEnter function tries to use the value updated in the input:
class App extends React.Component {
constructor(props){
super(props);
this.state = {
categories: [],
searchResults: [],
};
this.filterSearch = this.filterSearch.bind(this);
}
filterSearch(){
var el = document.getElementById('filter-results').value
console.log(el)
var result = this.state.categories.filter(row => {
var rx = new RegExp(el)
return rx.test(row['id'])
});
console.log(result)
}
render(){
return (
<div className="App">
<Header onEnter={this.filterSearch}/>
</div>
);
}
}
When I type something into the input, the element's value is logged to the console. The problem is, what is logged is always one character less than what I expect to see. If I type 'a', I get '', 'ab' => 'a', etc. I can understand conceptually that when the function is triggered and the logging occurs the value hasn't yet been updated, but I don't know how to wait for the value to be updated and then work with it. Can anyone help me?
Use onChange instead.
//change handler
handler(e) {
console.log(e.target.value)
}
//input's onChange event
onChange={ this.handler.bind(this) }
1) You should not be using native javascript to get value by id. This is not react way of doing.
App.js
import React from "react";
import ReactDOM from "react-dom";
import Header from "./Header";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
categories: [],
searchResults: []
};
this.filterSearch = this.filterSearch.bind(this);
}
filterSearch(value) {
console.log(value);
var result = this.state.categories.filter(row => {
var rx = new RegExp(value);
return rx.test(row["id"]);
});
console.log(result);
}
render() {
return (
<div className="App">
<Header onEnter={this.filterSearch} />
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
// Header.js
import React from "react";
export default class Header extends React.Component {
constructor(props) {
super(props);
}
handleChange = ({ target }) => {
this.setState({
[target.name]: target.value
});
this.props.onEnter(target.value);
};
render() {
return (
<div className="Header">
<div>
<input
onChange={this.handleChange}
name="filter-results"
className="full"
type="text"
placeholder="search kks"
/>
</div>
<div>
<button className="full">SEARCH</button>
</div>
</div>
);
}
}
I have a global variable called global.language. In my CustomHeader component, I have a Button that toggles the language global variable. What I want is to update all my screen components to reflect the language change.
I don't know if the best way to go is to get a reference to the Screens or to use an event library or if there are React friendly ways of doing this.
My CustomHeader.js looks like this:
export default class CustomHeader extends React.Component {
constructor(props) {
super(props);
this.toggleLanguage = this.toggleLanguage.bind(this);
}
render() {
return (
<Button onPress={ this.toggleLanguage } title="Language" accessibilityLabel="Toggle language" />
);
}
toggleLanguage() {
if (global.language == "PT") global.language = "EN";
else if (global.language == "EN") global.language = "PT";
}
}
My Screen.js renders numerous components called Event. This is what my Event.js looks like:
export default class Event extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<Card>
<Text>{Event.getTitle(this.props.data)}</Text>
</Card>
);
}
static getTitle(data) {
if (global.language === "PT") return data.title;
else if (global.language === "EN") return data.title_english;
}
}
Live sandbox
In details.
React.createContext we can just export to reuse. But this would be just "generic" context. Better encapsulate data and methods we need into custom container element and HOC:
import React from "react";
const context = React.createContext();
export class I18N extends React.Component {
state = {
language: "en"
};
setLanguage = language => {
this.setState({ language });
};
render() {
return (
<context.Provider
value={{ language: this.state.language, setLanguage: this.setLanguage }}
>
{this.props.children}
</context.Provider>
);
}
}
export function withI18n(Component) {
return props => (
<context.Consumer>
{i18nContext => <Component {...props} i18n={i18nContext} />}
</context.Consumer>
);
}
<I18N> is provider that will typically go just once on the topmost level.
And with HOC withI18n we are going to wrap every element that need access to our language value or ability to update this value.
import React from "react";
import ReactDOM from "react-dom";
import { I18N, withI18n } from "./i18n";
const Header = withI18n(function({i18n}) {
const setLang = ({ target: { value } }) => i18n.setLanguage(value);
return (
<div>
<input type="radio" value="en" checked={i18n.language === "en"} onChange={setLang} /> English
<input type="radio" value="fr" checked={i18n.language === "fr"} onChange={setLang} /> French
<input type="radio" value="es" checked={i18n.language === "es"} onChange={setLang} /> Spanish
</div>
);
});
const Body = withI18n(function(props) {
return <div>Current language is {props.i18n.language}</div>;
});
const rootElement = document.getElementById("root");
ReactDOM.render(<I18N>
<Header />
<Body />
</I18N>, rootElement);
And finally good article with some additional details: https://itnext.io/combining-hocs-with-the-new-reacts-context-api-9d3617dccf0b
I have a function that is used to change the state of a react component but I'm trying to pass the function in another file. I get the error that the function I'm trying to pass (changeView) is not defined.
This is the App.js
export default class App extends Component {
constructor() {
super();
this.state = {
language: "english",
render: ''
}
}
changeView(view, e){
console.log(view);
this.setState({render: view});
}
_renderSubComp(){
switch(this.state.render){
case 'overview': return <Overview />
case 'reviews': return <Reviews />
}
}
render() {
const {render} = this.state
return <Fragment>
<Header language={this.state.language} />
<Hero />
<Navigation render={render}/>
{this._renderSubComp()}
</Fragment>;
}
}
I'm trying to pass the changeView method to the Navigation.JS component, so I can change the active link as well as render the components listed in the _renderSubComp method above.
import React from "react";
import "./navigation.css";
import { changeView } from "../app";
export default function Navigation() {
return <div className="navigation">
<a onClick={this.changeView.bind(this,
'overview')}>Overview</a>
<a>Reviews</a>
</div>;
}
How should I pass the function to another file so it's able to change the state of my component and render the component I need.
You can't import a method like that. You will pass your function like any other prop to your component and you use there.
I've changed a few things. Firstly, I define changeView function as an arrow one, so we don't need to bind it. Secondly, I pass this function to the component as a prop. Thirdly, I used this function there like:
onClick={() => props.changeView('overview')}
As you can see it is props.changeView not state.changeView
Just go through the official documentation a little bit more. You are confused about states, props and how to pass them to your components.
class App extends React.Component {
constructor() {
super();
this.state = {
language: "english",
render: ''
}
}
changeView = (view, e) => {
console.log(view);
this.setState({ render: view });
}
render() {
const { render } = this.state
return <div>
<Navigation render={render} changeView={this.changeView} />
</div>;
}
}
const Navigation = (props) => {
return <div className="navigation">
<a onClick={() => props.changeView('overview')}>Overview</a>
<a>Reviews</a>
</div>;
}
ReactDOM.render(<App />, 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>