I'm trying to onDragMove to manually update an elements position. The shape itself is dragging around, and the is updating the objects, but it is not being rendered?
Same with onDragEnd. Both are updating the array of shapes correctly, but it is not appearing on the render, even though
import React, { useState, useEffect } from "react";
import { Stage, Layer, Rect } from "react-konva";
import "./styles.css";
export default function App() {
const [objects, setObject] = useState([{ id: "rect1", x: 50, y: 50 }]);
// Function
const updatePosition = (id) => {
let update = objects.map((entry) => {
if (entry.id !== id) return entry;
else return { ...entry, x: 100, y: 0 };
});
setObject(update);
};
// We can see the object is updated with the new coords
useEffect(() => {
console.log(objects);
});
return (
<main style={{ background: "lightgrey" }}>
<Stage width={800} height={800}>
<Layer>
{objects.map((object) => {
// This shows an updated X value correclty
console.log(object.x);
// It doesn't render the new x position at all
return (
<Rect
key={object.id}
fill={"green"}
width={200}
height={300}
x={object.x}
y={object.y}
draggable
onDragMove={() => updatePosition(object.id)}
onDragEnd={() => updatePosition(object.id)}
/>
);
})}
</Layer>
</Stage>
</main>
);
}
https://codesandbox.io/s/priceless-dust-cjr6z?file=/src/App.js:0-1323
From your demo, I see that you are setting the same {x, y} position to the shape:
const updatePosition = (id) => {
let update = objects.map((entry) => {
if (entry.id !== id) return entry;
else return { ...entry, x: 100, y: 0 };
});
setObject(update);
};
By default react-konva will set 100, 0 position just once. On the next render calls, properties for <Rect /> element are not changing. react-konva will update only CHANGED from previous render properties.
If you want to strictly set the last properties, you should use strict mode
Related
I have an x-range chart, and I need to add custom components (SVG icons) at the start of each data point ("x" prop value). Something like this (red circles are where custom components should be):
My idea is to place a custom component with position absolute, but I can't figure out how to transform timestamp values of the X axis to pixels. Or maybe there is a better solution?
Codesandbox demo
There are multiple ways to achieve what you want:
A. You can get a chart reference and use Axis.toPixels method to calculate the required coordinates:
export default function Chart() {
const chartComponentRef = useRef(null);
const [x1, setX1] = useState(0);
useEffect(() => {
if (chartComponentRef) {
const chart = chartComponentRef.current.chart;
const xAxis = chart?.xAxis[0];
const x1 = xAxis?.toPixels(Date.UTC(2022, 7, 10));
setX1(x1);
}
}, [chartComponentRef]);
return (
<div style={{ position: "relative" }}>
<HighchartsReact
ref={chartComponentRef}
highcharts={Highcharts}
options={staticOptions}
/>
<div style={{ position: "absolute", bottom: 70, left: x1 }}>ICON</div>
</div>
);
}
Live demo: https://codesandbox.io/s/highcharts-react-custom-componentt-ysjfh8?file=/src/Chart.js
API Reference: https://api.highcharts.com/class-reference/Highcharts.Axis#toPixels
B. You can also get coordinates from a point:
useEffect(() => {
if (chartComponentRef) {
const chart = chartComponentRef.current.chart;
const point = chart.series[0].points[2];
setX1(chart.plotLeft + point.plotX);
}
}, [chartComponentRef]);
Live demo: https://codesandbox.io/s/highcharts-react-custom-componentt-f7nveg?file=/src/Chart.js
C. Use Highcharts API to render and update the custom icons:
const staticOptions = {
chart: {
type: "xrange",
height: 200,
events: {
render: function () {
const chart = this;
const r = 10;
const distance = 25;
chart.series[0].points.forEach((point, index) => {
if (!point.customIcon) {
point.customIcon = chart.renderer
.circle()
.attr({
fill: "transparent",
stroke: "red",
"stroke-width": 2
})
.add();
}
point.customIcon.attr({
x: point.plotX + chart.plotLeft + r,
y:
point.plotY +
chart.plotTop +
(index % 2 ? distance : -distance),
r
});
});
}
}
},
...
};
Live demo: https://codesandbox.io/s/highcharts-react-custom-componentt-f-87eof0?file=/src/Chart.js
API Reference: https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#circle
Is there a better way, that is: (a) having to pass the child event back to the parent to be able to extract the stage/layer to then be able to do a konva node "find", and (b) having to "find" nodes using this approach (as using Konva-React JSX I don't have references to them in the code)
import { Stage, Layer, Text } from "react-konva";
import { KonvaEventObject } from "konva/lib/Node";
// ----------------------------------------------
type TestTileProps = {
id: String;
hodh: (e: KonvaEventObject<DragEvent>) => void;
};
const TestTile = function ({ id, hodh }: TestTileProps) {
const handleOnDragMove = (e: KonvaEventObject<DragEvent>) => {
hodh(e);
};
return (
<Text
y={20}
text={id + " <=="}
draggable={true}
onDragMove={handleOnDragMove}
/>
);
};
// ----------------------------------------------
const App = () => {
const higherOrderDragHandler = (e: KonvaEventObject<DragEvent>) => {
const layer = e.target.getLayer();
const textNode = layer.find(".MainText")[0];
textNode.position({
x: e.target.position().y,
y: textNode.position().y
});
};
return (
<Stage width={window.innerWidth} height={window.innerHeight}>
<Layer>
<Text name="MainText" text="Heading 123" />
<TestTile id={"Value pass"} hodh={higherOrderDragHandler} />
</Layer>
</Stage>
);
};
export default App;
// ----------------------------------------------
I was following this tutorial on how to build a whiteboard with react and konva and it provides an undo function for shapes but does not work for lines because lines are not added to the layer in the same way. How can I implement undo for free draw line?
EDIT:
To expand on my question, here is the relevant code:
I have a public repo that you can check out (and make a PR if that's easier).
https://github.com/ChristopherHButler/Sandbox-react-whiteboard
I have also have a demo you can try out here:
https://whiteboard-rho.now.sh/
Here is the relevant code
line component:
import Konva from "konva";
export const addLine = (stage, layer, mode = "brush") => {
let isPaint = false;
let lastLine;
stage.on("mousedown touchstart", function(e) {
isPaint = true;
let pos = stage.getPointerPosition();
lastLine = new Konva.Line({
stroke: mode == "brush" ? "red" : "white",
strokeWidth: mode == "brush" ? 5 : 20,
globalCompositeOperation:
mode === "brush" ? "source-over" : "destination-out",
points: [pos.x, pos.y],
draggable: mode == "brush",
});
layer.add(lastLine);
});
stage.on("mouseup touchend", function() {
isPaint = false;
});
stage.on("mousemove touchmove", function() {
if (!isPaint) {
return;
}
const pos = stage.getPointerPosition();
let newPoints = lastLine.points().concat([pos.x, pos.y]);
lastLine.points(newPoints);
layer.batchDraw();
});
};
HomePage component:
import React, { useState, createRef } from "react";
import { v1 as uuidv1 } from 'uuid';
import ButtonGroup from "react-bootstrap/ButtonGroup";
import Button from "react-bootstrap/Button";
import { Stage, Layer } from "react-konva";
import Rectangle from "../Shapes/Rectangle";
import Circle from "../Shapes/Circle";
import { addLine } from "../Shapes/Line";
import { addTextNode } from "../Shapes/Text";
import Image from "../Shapes/Image";
const HomePage = () => {
const [rectangles, setRectangles] = useState([]);
const [circles, setCircles] = useState([]);
const [images, setImages] = useState([]);
const [selectedId, selectShape] = useState(null);
const [shapes, setShapes] = useState([]);
const [, updateState] = useState();
const stageEl = createRef();
const layerEl = createRef();
const fileUploadEl = createRef();
const getRandomInt = max => {
return Math.floor(Math.random() * Math.floor(max));
};
const addRectangle = () => {
const rect = {
x: getRandomInt(100),
y: getRandomInt(100),
width: 100,
height: 100,
fill: "red",
id: `rect${rectangles.length + 1}`,
};
const rects = rectangles.concat([rect]);
setRectangles(rects);
const shs = shapes.concat([`rect${rectangles.length + 1}`]);
setShapes(shs);
};
const addCircle = () => {
const circ = {
x: getRandomInt(100),
y: getRandomInt(100),
width: 100,
height: 100,
fill: "red",
id: `circ${circles.length + 1}`,
};
const circs = circles.concat([circ]);
setCircles(circs);
const shs = shapes.concat([`circ${circles.length + 1}`]);
setShapes(shs);
};
const drawLine = () => {
addLine(stageEl.current.getStage(), layerEl.current);
};
const eraseLine = () => {
addLine(stageEl.current.getStage(), layerEl.current, "erase");
};
const drawText = () => {
const id = addTextNode(stageEl.current.getStage(), layerEl.current);
const shs = shapes.concat([id]);
setShapes(shs);
};
const drawImage = () => {
fileUploadEl.current.click();
};
const forceUpdate = React.useCallback(() => updateState({}), []);
const fileChange = ev => {
let file = ev.target.files[0];
let reader = new FileReader();
reader.addEventListener(
"load",
() => {
const id = uuidv1();
images.push({
content: reader.result,
id,
});
setImages(images);
fileUploadEl.current.value = null;
shapes.push(id);
setShapes(shapes);
forceUpdate();
},
false
);
if (file) {
reader.readAsDataURL(file);
}
};
const undo = () => {
const lastId = shapes[shapes.length - 1];
let index = circles.findIndex(c => c.id == lastId);
if (index != -1) {
circles.splice(index, 1);
setCircles(circles);
}
index = rectangles.findIndex(r => r.id == lastId);
if (index != -1) {
rectangles.splice(index, 1);
setRectangles(rectangles);
}
index = images.findIndex(r => r.id == lastId);
if (index != -1) {
images.splice(index, 1);
setImages(images);
}
shapes.pop();
setShapes(shapes);
forceUpdate();
};
document.addEventListener("keydown", ev => {
if (ev.code == "Delete") {
let index = circles.findIndex(c => c.id == selectedId);
if (index != -1) {
circles.splice(index, 1);
setCircles(circles);
}
index = rectangles.findIndex(r => r.id == selectedId);
if (index != -1) {
rectangles.splice(index, 1);
setRectangles(rectangles);
}
index = images.findIndex(r => r.id == selectedId);
if (index != -1) {
images.splice(index, 1);
setImages(images);
}
forceUpdate();
}
});
return (
<div className="home-page">
<ButtonGroup style={{ marginTop: '1em', marginLeft: '1em' }}>
<Button variant="secondary" onClick={addRectangle}>
Rectangle
</Button>
<Button variant="secondary" onClick={addCircle}>
Circle
</Button>
<Button variant="secondary" onClick={drawLine}>
Line
</Button>
<Button variant="secondary" onClick={eraseLine}>
Erase
</Button>
<Button variant="secondary" onClick={drawText}>
Text
</Button>
<Button variant="secondary" onClick={drawImage}>
Image
</Button>
<Button variant="secondary" onClick={undo}>
Undo
</Button>
</ButtonGroup>
<input
style={{ display: "none" }}
type="file"
ref={fileUploadEl}
onChange={fileChange}
/>
<Stage
style={{ margin: '1em', border: '2px solid grey' }}
width={window.innerWidth * 0.9}
height={window.innerHeight - 150}
ref={stageEl}
onMouseDown={e => {
// deselect when clicked on empty area
const clickedOnEmpty = e.target === e.target.getStage();
if (clickedOnEmpty) {
selectShape(null);
}
}}
>
<Layer ref={layerEl}>
{rectangles.map((rect, i) => {
return (
<Rectangle
key={i}
shapeProps={rect}
isSelected={rect.id === selectedId}
onSelect={() => {
selectShape(rect.id);
}}
onChange={newAttrs => {
const rects = rectangles.slice();
rects[i] = newAttrs;
setRectangles(rects);
}}
/>
);
})}
{circles.map((circle, i) => {
return (
<Circle
key={i}
shapeProps={circle}
isSelected={circle.id === selectedId}
onSelect={() => {
selectShape(circle.id);
}}
onChange={newAttrs => {
const circs = circles.slice();
circs[i] = newAttrs;
setCircles(circs);
}}
/>
);
})}
{images.map((image, i) => {
return (
<Image
key={i}
imageUrl={image.content}
isSelected={image.id === selectedId}
onSelect={() => {
selectShape(image.id);
}}
onChange={newAttrs => {
const imgs = images.slice();
imgs[i] = newAttrs;
}}
/>
);
})}
</Layer>
</Stage>
</div>
);
}
export default HomePage;
As a solution, you should just use the same react modal for lines. It is not recommended to create shape instances manually (like new Konva.Line) when you work with react-konva.
Just define your state and make a correct render() from it, as you do in HomePage component.
You may store all shapes in one array. Or use a separate for lines. So to draw lines in react-konva way you can do this:
const App = () => {
const [lines, setLines] = React.useState([]);
const isDrawing = React.useRef(false);
const handleMouseDown = (e) => {
isDrawing.current = true;
const pos = e.target.getStage().getPointerPosition();
setLines([...lines, [pos.x, pos.y]]);
};
const handleMouseMove = (e) => {
// no drawing - skipping
if (!isDrawing.current) {
return;
}
const stage = e.target.getStage();
const point = stage.getPointerPosition();
let lastLine = lines[lines.length - 1];
// add point
lastLine = lastLine.concat([point.x, point.y]);
// replace last
lines.splice(lines.length - 1, 1, lastLine);
setLines(lines.concat());
};
const handleMouseUp = () => {
isDrawing.current = false;
};
return (
<Stage
width={window.innerWidth}
height={window.innerHeight}
onMouseDown={handleMouseDown}
onMousemove={handleMouseMove}
onMouseup={handleMouseUp}
>
<Layer>
<Text text="Just start drawing" />
{lines.map((line, i) => (
<Line key={i} points={line} stroke="red" />
))}
</Layer>
</Stage>
);
};
Demo: https://codesandbox.io/s/hungry-architecture-v380jlvwrl?file=/index.js
Then the next step is how to implement undo/redo. You just need to keep a history of state changes. Take a look here for demo: https://konvajs.org/docs/react/Undo-Redo.html
If I understand this right you saying that for shapes which are added individually there is an easy 'undo' process, but for lines which use an array of points for their segments, there is no simple undo - and no code in the tutorial you are following?
I can't give you a react code sample but I can explain some of the concepts you need to code up.
The 'freehand line' in your whiteboard is created as a sequence of points. You mousedown and the first point is noted, then you move the mouse and on each movemove event that fires the current mouse position is added to the end of the array. By the time you complete the line and mouseup fires, you have thrown multiple points into the line array.
In the Konvajs line tutorial it states:
To define the path of the line you should use points property. If you
have three points with x and y coordinates you should define points
property as: [x1, y1, x2, y2, x3, y3].
[Because...] Flat array of numbers should work faster and use less memory than
array of objects.
So - your line points are added as separate values into the line.points array.
Now lets think about undo - you are probably there already but I'll write it out anyway - to undo a single segment of the line you need to erase the last 2 entries in the array. To erase the entire line - well you can use the standard shape.remove() or shape.destroy() methods.
In the following snippet the two buttons link to code to 'undo' lines. The 'Undo by segment' button shows how to pop the last two entries in the line.points array to remove a segment of the line, and the 'Undo by line' button removes entire lines. This is not a react example specifically, but you will in the end create something very close to this in your react case.
// Code to erase line one segment at a time.
$('#undosegment').on('click', function(){
// get the last line we added to the canvas - tracked via lines array in this demo
if (lines.length === 0){
return;
}
lastLine = lines[lines.length - 1];
let pointsArray = lastLine.points(); // get current points in line
if (pointsArray.length === 0){ // no more points so destroy this line object.
lastLine.destroy();
layer.batchDraw();
lines.pop(); // remove from our lines-tracking array.
return;
}
// remove last x & y entrie, pop appears to be fastest way to achieve AND adjust array length
pointsArray.pop(); // remove the last Y pos
pointsArray.pop(); // remove the last X pos
lastLine.points(pointsArray); // give the points back into the line
layer.batchDraw();
})
// Code to erase entire lines.
$('#undoline').on('click', function(){
// get the last line we added to the canvas - tracked via lines array in this demo
if (lines.length === 0){
return;
}
lastLine = lines[lines.length - 1];
lastLine.destroy(); // remove from our lines-tracking array.
lines.pop();
layer.batchDraw();
})
// code from here on is all about drawing the lines.
let
stage = new Konva.Stage({
container: 'container',
width: $('#container').width(),
height: $('#container').height()
}),
// add a layer to draw on
layer = new Konva.Layer();
stage.add(layer);
stage.draw();
let isPaint = false;
let lastLine;
let lines = [];
stage.on('mousedown', function(){
isPaint = true;
let pos = stage.getPointerPosition();
lastLine = new Konva.Line({ stroke: 'magenta', strokeWidth: 4, points: [pos.x, pos.y]});
layer.add(lastLine);
lines.push(lastLine);
})
stage.on("mouseup touchend", function() {
isPaint = false;
});
stage.on("mousemove touchmove", function() {
if (!isPaint) {
return;
}
const pos = stage.getPointerPosition();
let newPoints = lastLine.points().concat([pos.x, pos.y]);
lastLine.points(newPoints);
layer.batchDraw();
});
body {
margin: 10;
padding: 10;
overflow: hidden;
background-color: #f0f0f0;
}
#container {
border: 1px solid silver;
width: 500px;
height: 300px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://unpkg.com/konva#^3/konva.min.js"></script>
<p>Click and drag to draw a line </p>
<p>
<button id='undosegment'>Undo by segment</button> <button id='undoline'>Undo by line</button>
</p>
<div id="container"></div>
I have implemented drag n drop list with panResponder and ScrollView. I want to be able to scroll the list even when I touch the item. Problem is that the item moves when I do the gesture to scroll. Of course I also want to be able to move the item but now it has the same gesture as scroll. I want to overcome it by enabling dragging the element only after it was long pressed (1,5 sec). How to implement it? I thought to use Touchable as an element with onPressIn / onPressOut just like described here: http://browniefed.com/blog/react-native-press-and-hold-button-actions/
and somehow to enable panResponder after the time period, but I don't know how to enable it programmatically.
Right now this is my code for element in the list:
class AccountItem extends Component {
constructor(props) {
super(props);
this.state = {
pan: new Animated.ValueXY(),
zIndex: 0,
}
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: () => true,
onPanResponderGrant: (e, gestureState) => {
this.setState({ zIndex: 100 });
this.props.disableScroll();
},
onPanResponderMove: Animated.event([null, {
dx: this.state.pan.x,
dy: this.state.pan.y,
}]),
onPanResponderRelease: (e, gesture) => {
this.props.submitNewPositions();
Animated.spring(
this.state.pan,
{toValue:{ x:0, y:0 }}
).start();
this.setState({ zIndex: 0 });
this.props.enableScroll();
}
})
}
meassureMyComponent = (event) => {
const { setElementPosition } = this.props;
let posY = event.nativeEvent.layout.y;
setElementPosition(posY);
}
render() {
const {name, index, onChangeText, onRemoveAccount} = this.props;
return (
<Animated.View
style={[this.state.pan.getLayout(), styles.container, {zIndex: this.state.zIndex}]}
{...this.panResponder.panHandlers}
onLayout={this.meassureMyComponent}
>
some other components...
</Animated.View>
)
}
}
export default AccountItem;
I met the same issue with you. My solution is to define 2 different panResponder handler for onLongPress and normal behaviour.
_onLongPressPanResponder(){
return PanResponder.create({
onPanResponderTerminationRequest: () => false,
onStartShouldSetPanResponderCapture: () => true,
onPanResponderMove: Animated.event([
null, {dx: this.state.pan.x, dy: this.state.pan.y},
]),
onPanResponderRelease: (e, {vx, vy}) => {
this.state.pan.flattenOffset()
Animated.spring(this.state.pan, { //This will make the draggable card back to its original position
toValue: 0
}).start();
this.setState({panResponder: undefined}) //Clear panResponder when user release on long press
}
})
}
_normalPanResponder(){
return PanResponder.create({
onPanResponderTerminationRequest: () => false,
onStartShouldSetPanResponderCapture: () => true,
onPanResponderGrant: (e, gestureState) => {
this.state.pan.setOffset({x: this.state.pan.x._value, y: this.state.pan.y._value});
this.state.pan.setValue({x: 0, y: 0})
this.longPressTimer=setTimeout(this._onLongPress, 400) // this is where you trigger the onlongpress panResponder handler
},
onPanResponderRelease: (e, {vx, vy}) => {
if (!this.state.panResponder) {
clearTimeout(this.longPressTimer); // clean the timeout handler
}
}
})
}
Define your _onLongPress function:
_onLongPress(){
// you can add some animation effect here as wll
this.setState({panResponder: this._onLongPressPanResponder()})
}
Define your constructor:
constructor(props){
super(props)
this.state = {
pan: new Animated.ValueXY()
};
this._onLongPress = this._onLongPress.bind(this)
this._onLongPressPanResponder = this._onLongPressPanResponder.bind(this)
this._normalPanResponder = this._normalPanResponder.bind(this)
this.longPressTimer = null
}
Finally, before you render, you should switch to different panResponder handlers according to the state:
let panHandlers = {}
if(this.state.panResponder){
panHandlers = this.state.panResponder.panHandlers
}else{
panHandlers = this._normalPanResponder().panHandlers
}
Then attach the panHandlers to your view {...panHandlers}
You can even change the css for different panHandlers to show different effect.
If your only issue is that ScrollView scrolls when moving item, then I'll suggest simply to disable scrolling of parent for movement period.
Like:
//component with ScrollView:
...
constructor() {
super()
this.state = {scrolling: true}
this.enableScroll = this.enableScroll.bind(this)
this.disableScroll = this.disableScroll.bind(this)
}
// inject those methods into Drag&Drop item as props:
enableScroll() {
this.setState({scrolling: true})
}
disableScroll() {
this.setState({scrolling: false})
}
...
<ScrollView scrollEnabled={this.state.scrolling} ... />
...
//component with drag&drop item:
...
onPanResponderGrant() {
...
this.props.disableScroll()
...
}
onPanResponderRelease() {
this.props.enableScroll()
}
Make sure to cover all cases of release gesture (like onPanResponderTerminate etc.)
You can do this using a ref value to store if dragging should be enabled, and this can be accessed within the PanResponder. Using a ref ensures that the value won't be stale w.r.t the PanResponder; that is, the reference to the ref will be fixed at the initialisation of the PanResponder, but the underlying .current value can change. (This is unlike a useState value, which would be stale past the initialisation of the PanResponder.)
e.g.
const dragEnabledRef = useRef(false);
const pan = useRef(
PanResponder.create({
onStartShouldSetPanResponder: () => dragEnabledRef.current,
onStartShouldSetPanResponderCapture: () => dragEnabledRef.current,
onMoveShouldSetPanResponder: () => dragEnabledRef.current,
onMoveShouldSetPanResponderCapture: () => dragEnabledRef.current,
...
onPanResponderRelease: () => {
...
dragEnabledRef.current = false
}
})
).current
return (
<Pressable onLongPress={() => {
dragEnabledRef.current = true
}}>
{children}
</Pressable>
);
I copied the code from here.
This throws this warning:
.
How to fix this warning?
Code:
'use strict';
var React = require('react-native');
// I have import the ScrollView and RefreshControl
var{
StyleSheet,
Image,
ScrollView,
RefreshControl,
View,
} = React;
var Carousel = require('react-native-looped-carousel');
var Dimensions = require('Dimensions');
var {width, height} = Dimensions.get('window');
var NewsListView = React.createClass({
getInitialState: function () {
return {
isRefreshing: false,
loaded: 0,
};
},
componentDidMount: function () {
},
render: function () {
return (
// if I remove RefreshControl , the warming missing. how to fix this problem
<ScrollView
style={styles.scrollview}
refreshControl={
<RefreshControl
refreshing={this.state.isRefreshing}
onRefresh={this._onRefresh}
tintColor="#ff0000"
title="Loading..."
/>
}>
<View>
<Carousel delay={5000} style={{width: width, height: height/4 }}>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner.png')
}
style={{width: width, height: height/4}}
/>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner2.png')}
style={{width: width, height: height/4}}
/>
<Image
source={require('RT_XiaoYiSiGou/Image/img_banner3.png')}
style={{width: width, height: height/4}}
/>
</Carousel>
</View>
</ScrollView>
);
},
_onRefresh() {
this.setState({isRefreshing: true});
setTimeout(() => {
this.setState({
loaded: this.state.loaded + 10,
isRefreshing: false,
});
}, 5000);
},
});
var styles = StyleSheet.create({
scrollview: {
flex: 1,
},
});
module.exports = NewsListView;
What I "suggest" because I can't do more from your code is:
1) The error you get is because you do not call the React.createElement correctly. You should write your code in simple segments, I suggest chopping it up in three parts, definition, creation and render...
// define your element
var definitionObject = {
// a property called render which is a function which returns your markup.
render: function() {
return (
<h1 className="peterPan">
Peter Pan.
</h1>
);
}
}
// create the actual element
var PeterPanElement = React.createClass(definitionObject);
ReactDOM.render(
<PeterPanElement />,
document.getElementById('willBeReplacedByPeterPanElement')
);
I hope you agree I can't deduce more from your question, if you clean the question up we might be able to help you out more...